void wizard::WsfEditor::SetTextFormat(size_t aStart, size_t aCount, const QTextCharFormat& aFmt)
{
// 将字节位置转换为Qt字符位置以正确处理中文字符
size_t qtStart = BytePosToQtPos(aStart);
size_t qtEnd = BytePosToQtPos(aStart + aCount);
size_t qtCount = qtEnd - qtStart;
size_t end = std::min(qtStart + qtCount, mCurrentStylePos + mCurrentStyleLength);
if (end >= mCurrentStylePos)
{
for (size_t i = std::max(mCurrentStylePos, qtStart) - mCurrentStylePos; i < end - mCurrentStylePos; ++i)
{
mFormatChanges[ut::cast_to_int(i)] = aFmt;
}
}
}
void wizard::WsfEditor::MergeTextFormat(size_t aStart, size_t aCount, const QTextCharFormat& aFmt)
{
// 将字节位置转换为Qt字符位置以正确处理中文字符
size_t qtStart = BytePosToQtPos(aStart);
size_t qtEnd = BytePosToQtPos(aStart + aCount);
size_t qtCount = qtEnd - qtStart;
size_t end = std::min(qtStart + qtCount, mCurrentStylePos + mCurrentStyleLength);
if (end >= mCurrentStylePos)
{
for (size_t i = std::max(mCurrentStylePos, qtStart) - mCurrentStylePos; i < end - mCurrentStylePos; ++i)
{
mFormatChanges[ut::cast_to_int(i)].merge(aFmt);
}
}
}
size_t wizard::WsfEditor::BytePosToQtPos(size_t aBytePos)
{
// 如果没有中文字符,字节位置和字符位置是相同的
if (aBytePos == 0) return 0;
// 获取当前整个文档内容
QString fullText = toPlainText();
// 将文档转换为UTF-8字节流
std::string utf8Text = ToAscii(fullText);
// 如果字节位置超出范围,返回文档末尾
if (aBytePos >= utf8Text.size()) {
return fullText.length();
}
// 使用二分查找找到对应的Qt字符位置
int left = 0, right = fullText.length();
while (left < right) {
int mid = (left + right) / 2;
// 获取从开始到mid位置的Qt字符串
QString partialText = fullText.left(mid);
std::string partialUtf8 = ToAscii(partialText);
if (partialUtf8.size() < aBytePos) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}bool wizard::TextSource::ReadSource(bool aAlwaysFullyReload)
{
bool loaded(false);
UtPath::StatData statData;
GetFilePath().Stat(statData);
if (statData.mStatType == UtPath::cDIRECTORY)
{
return false;
}
if (statData.mStatType == UtPath::cFILE)
{
if (statData.mFileSizeBytes < (size_t)cMAXIMUM_FILE_SIZE)
{
// After first read, ensure the parser isn't running.
if (mLoaded)
{
GetWorkspace()->WaitForAbortParsing();
}
if (UtTextDocument::ReadFile(GetFilePath()))
{
SetDeleted(false);
SetModified(false);
bool requiresParse = GetProject()->SourceReloaded(this);
if (requiresParse)
{
GetProject()->TriggerReparse();
}
loaded = true;
}
}
else
{
const QString msg("The file %1 is too large to open. (%2 MB).");
const QString filePath(QString::fromUtf8(mFilePath.GetSystemPath().c_str()));
const double sizeMb = (statData.mFileSizeBytes / 1000000.0);
QMessageBox::warning(nullptr, "File too large", msg.arg(filePath).arg(sizeMb));
if (mLoaded)
{
SetModified(false);
Unload();
}
loaded = false;
}
mFileSignature.Update(mFilePath);
}
else if (statData.mStatType == UtPath::cSTAT_ERROR)
{
Clear();
Insert(0, "\0", 1); // null terminator
SetDeleted(true);
SetModified(false);
loaded = true;
}
if (!mViews.empty())
{
ReloadEditor(*mViews[0]->mEditorPtr, false, true, aAlwaysFullyReload);
}
if (loaded)
{
mPendingChanges.clear();
mAppliedChanges.clear();
}
mLoaded = loaded;
return loaded;
}void wizard::TextSource::ReloadEditor(Editor& aEditor, bool aInitialLoad, bool aForceUnmodified, bool aForceReload)
{
aEditor.BeginNonUserAction();
if (aInitialLoad || aForceReload)
{
// Copy text to scintilla
char* textPtr = GetText().GetPointer(0);
aEditor.BeginNonUserAction();
aEditor.document()->setPlainText(QString::fromUtf8(textPtr));
QTextCursor cur = aEditor.textCursor();
cur.setPosition(0);
aEditor.setTextCursor(cur);
aEditor.EndNonUserAction();
if (aInitialLoad)
{
aEditor.document()->clearUndoRedoStacks();
aEditor.document()->setModified(false);
}
}
else
{
// Diff this text document with scintilla's copy. Apply only the changes.
std::string oldText = aEditor.ToAscii(aEditor.ToPlainText());
QVector<TextSourceChange> changes;
DiffDocuments(oldText.c_str(), GetPointer(), changes);
if (!changes.empty())
{
int firstChangePos = -1;
QTextCursor cur = aEditor.textCursor();
cur.beginEditBlock();
for (int i = 0; i < changes.size(); ++i)
{
const TextSourceChange& change = changes[i];
if (i == 0)
firstChangePos = ut::cast_to_int(change.mPos);
ApplyChangeToQt(changes[i], cur);
}
cur.endEditBlock();
if (!aForceUnmodified)
{
SetModified(true, true);
}
// scroll to first change
if (firstChangePos != -1)
{
QTextCursor cur = aEditor.textCursor();
cur.setPosition(firstChangePos);
aEditor.setTextCursor(cur);
aEditor.centerCursor();
}
}
if (!mModified)
{
// aEditor.SendScintilla(SCI_SETSAVEPOINT);
}
}
aEditor.EndNonUserAction();
aEditor.ReloadComplete();
}void wizard::TextSource::SaveAs()
{
UtPath dir = GetFilePath();
dir.Up();
QFileDialog dlg(nullptr, "Save File As", dir.GetSystemPath().c_str(), "*.*");
dlg.setDefaultSuffix("txt");
dlg.selectFile(GetFileName().c_str());
dlg.setAcceptMode(QFileDialog::AcceptSave);
dlg.setFileMode(QFileDialog::AnyFile);
if (dlg.exec())
{
QStringList selFiles = dlg.selectedFiles();
if (selFiles.length() == 1)
{
// Ensure the source is ready
WaitForSourceModifications();
std::string newFilePath = selFiles[0].toUtf8().toStdString();
std::ofstream outfile(newFilePath.c_str(), std::ios::binary);
while (!outfile)
{
std::stringstream ss;
ss << "Could not save file " + newFilePath + ", check that the file/directory is writable.";
int bn = QMessageBox::warning(nullptr, "Could not save", ss.str().c_str(), "Retry", "Cancel");
if (bn != 0)
{
break;
}
}
if (outfile)
{
WriteFile(outfile);
outfile.close();
UtPath newFile(newFilePath);
if (newFile.Stat() == UtPath::cFILE)
{
// WIZARD_TODO: Open the file for the user?
// GetProject()->AddTransientFile(newFile);
}
emit TextSourceSignals::GetInstance().requestBackup();
}
}
}
}
void wizard::TextSource::CopyPathToClipboard()
{
QApplication::clipboard()->setText(QString::fromUtf8(GetSystemPath().c_str()));
}void wizard::TextSource::ApplyChangeToQt(const TextSourceChange& aChange, QTextCursor& aCursor)
{
if (aCursor.document()->toPlainText().size() < static_cast<int>(aChange.mPos))
{
// Adding at the end of the document
aCursor.movePosition(QTextCursor::End);
aCursor.insertText("\n");
}
aCursor.setPosition(ut::cast_to_int(aChange.mPos));
aCursor.setPosition(ut::cast_to_int(aChange.mPos + aChange.mCharsRemoved), QTextCursor::KeepAnchor);
// 正确处理UTF-8字符串到Qt的转换
aCursor.insertText(QString::fromUtf8(aChange.mText.c_str()));
}
void wizard::TextSource::FindIncludeLocations()
{
if (GetProject())
{
GetProject()->FindIncludes(this);
}
}
void wizard::TextSource::SaveAndStore()
{
SaveWithNotifications();
emit TextSourceSignals::GetInstance().requestBackup();
}
void wizard::TextSource::BrowseContainingFolder()
{
UtPath path = mFilePath;
path.Up();
QString pathStr("file:///");
pathStr += QString::fromUtf8(path.GetSystemPath().c_str());
QDesktopServices::openUrl(QUrl(pathStr));
}// 将Qt字符位置转换为对应的UTF-8字节位置
size_t wizard::Editor::QtPosToUtf8Pos(int aQtPos)
{
if (aQtPos <= 0) return 0;
// 获取从开始到指定位置的文本
QTextCursor cur(document());
cur.setPosition(0);
cur.setPosition(aQtPos, QTextCursor::KeepAnchor);
QString partialText = cur.selectedText();
// 转换为UTF-8并返回字节长度
std::string utf8Text = ToAscii(partialText);
return utf8Text.size();
}
// 将UTF-8字节位置转换为对应的Qt字符位置
int wizard::Editor::Utf8PosToQtPos(size_t aUtf8Pos)
{
if (aUtf8Pos == 0) return 0;
QString fullText = toPlainText();
std::string fullUtf8 = ToAscii(fullText);
if (aUtf8Pos >= fullUtf8.size()) {
return fullText.length();
}
// 使用二分查找找到对应的Qt位置
int left = 0, right = fullText.length();
while (left < right) {
int mid = (left + right) / 2;
size_t midUtf8Pos = QtPosToUtf8Pos(mid);
if (midUtf8Pos < aUtf8Pos) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
std::string wizard::Editor::ToAscii(const QString& aText)
{
// 处理段落分隔符,然后转换为UTF-8
QString processedText = aText;
processedText.replace(QChar(0x2029), QChar('\n')); // paragraph separator
// 直接使用UTF-8编码保持中文字符
return processedText.toUtf8().toStdString();
} void wizard::Editor::DocContentsChange(int aFrom, int aCharsRemoves, int aCharsAdded)
{
if (mNonUserAction > 0)
{
return;
}
// 简化处理:对于任何变化,都重新同步整个文档内容
// 这避免了复杂的位置转换问题,特别是中英文混合的情况
mSourcePtr->HandleDelete(0, 0x0fffffff);
QTextCursor cur(document());
cur.setPosition(0);
cur.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
QString newText = cur.selectedText();
// Convert to UTF-8 representation
std::string text = ToAscii(newText);
// 使用UTF-8字符串的实际字节长度
mSourcePtr->HandleInsert(0, text.size(), text.c_str());
}void wizard::ProjectWorkspace::NewProject()
{
// Use the location of the last opened project
// otherwise use the user's home directory
// else use the location of the executable
QString newLocationDir = QDir::currentPath();
if (!QDir::current().exists())
{
// Absolute path of the user's home directory
newLocationDir = QDir::toNativeSeparators(QDir::homePath()); // Home directory
// openLocationDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); // Documents directory
if (newLocationDir.isEmpty())
{
newLocationDir = QString::fromStdString(UtPath::GetExePath().GetSystemPath());
}
}
// Get the new project file name
QString fileName = QFileDialog::getSaveFileName(nullptr, "New Project", newLocationDir, "AFSIM Project (*.afproj)");
if (!fileName.isEmpty() &&
// set the working directory to the new project's directory
wizRunMgr.SetWorkingDirectoryToProject(fileName))
{
// 使用UTF-8编码处理文件名
std::string utf8FileName = fileName.toUtf8().toStdString();
UtPath fileNamePath(utf8FileName);
UtPath filePath = fileNamePath;
filePath.Up();
Project* projectPtr = new Project(this);
projectPtr->SetProjectLocation(filePath.GetSystemPath(), fileNamePath);
}
}wizard::Runner::Runner(int& argc,
char* argv[],
const char* aCompanyStr,
const char* aCompanyDomainStr,
const char* aProductNameStr,
const char* aProductVersionStr)
{
// Get the executable path
// Trim the name of the executable
mBinDir = UtPath::GetExePath();
mBinDir.Up();
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
mApp = ut::make_unique<QApplication>(argc, argv);
// 设置UTF-8编码支持中文
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
#endif
mApp->setQuitOnLastWindowClosed(true);
mApp->setWindowIcon(QIcon(":icons/wizard_logo_icon.png"));
qApp->setOrganizationName(aCompanyStr);
qApp->setOrganizationDomain(aCompanyDomainStr);
qApp->setApplicationName(aProductNameStr);
qApp->setApplicationDisplayName(aProductNameStr);
qApp->setApplicationVersion(aProductVersionStr);
}void Scanner::Init()
{
NewTokCb = nullptr;
mNewTokenDataPtr = nullptr;
EOL = '\n';
eofSym = 0;
// ***Declarations Begin
maxT = 58;
noSym = 58;
int i;
for (i = 65; i <= 90; ++i)
start.set(i, 1);
for (i = 95; i <= 95; ++i)
start.set(i, 1);
for (i = 97; i <= 122; ++i)
start.set(i, 1);
for (i = 48; i <= 57; ++i)
start.set(i, 31);
for (i = 34; i <= 34; ++i)
start.set(i, 7);
start.set(46, 32);
start.set(39, 9);
start.set(59, 13);
start.set(40, 14);
start.set(41, 15);
start.set(61, 33);
start.set(33, 43);
start.set(62, 44);
start.set(60, 45);
start.set(43, 34);
start.set(45, 35);
start.set(38, 20);
start.set(124, 22);
start.set(125, 24);
start.set(44, 25);
start.set(42, 46);
start.set(47, 47);
start.set(123, 38);
start.set(58, 39);
start.set(94, 40);
start.set(91, 41);
start.set(93, 42);
start.set(Buffer::EoF, -1);
keywords.set("do", 26);
keywords.set("if", 27);
keywords.set("for", 28);
keywords.set("foreach", 29);
keywords.set("in", 30);
keywords.set("else", 31);
keywords.set("while", 32);
keywords.set("break", 33);
keywords.set("continue", 34);
keywords.set("return", 35);
keywords.set("null", 36);
keywords.set("NULL", 37);
keywords.set("true", 38);
keywords.set("false", 39);
keywords.set("string", 40);
keywords.set("int", 41);
keywords.set("double", 42);
keywords.set("char", 43);
keywords.set("bool", 44);
keywords.set("global", 45);
keywords.set("static", 46);
keywords.set("extern", 47);
// ***Declarations End
tvalLength = 128;
tval = new cocochar_t[tvalLength]; // text of current token
// COCO_HEAP_BLOCK_SIZE byte heap + pointer to next heap block
heap = malloc(COCO_HEAP_BLOCK_SIZE + sizeof(void*));
firstHeap = heap;
heapEnd = (void**)(((char*)heap) + COCO_HEAP_BLOCK_SIZE);
*heapEnd = nullptr;
heapTop = heap;
if (sizeof(Token) > COCO_HEAP_BLOCK_SIZE)
{
ut::log::fatal() << "Too small COCO_HEAP_BLOCK_SIZE.";
exit(1);
}
pos = -1;
line = 1;
col = 0;
charPos = -1;
oldEols = 0;
NextCh();
#if !COCO_USE_INLINE_BUFFER
bool hasUtf8Bom = false;
if (ch == 0xEF)
{ // check optional byte order mark for UTF-8
NextCh();
int ch1 = ch;
NextCh();
int ch2 = ch;
if (ch1 == 0xBB && ch2 == 0xBF)
{
hasUtf8Bom = true;
}
else
{
// 不是UTF-8 BOM,回退到开始位置
buffer->SetPos(0);
pos = -1;
line = 1;
col = 0;
charPos = -1;
NextCh();
}
}
// 默认启用UTF-8支持,无论是否有BOM
// 这样可以支持没有BOM的UTF-8文件(包含中文的脚本文件)
Buffer* oldBuf = buffer;
buffer = new UTF8Buffer(buffer);
if (hasUtf8Bom)
{
col = 0;
charPos = -1;
NextCh(); // 跳过BOM
}
else
{
// 重新开始读取,使用UTF8Buffer
buffer->SetPos(0);
pos = -1;
line = 1;
col = 0;
charPos = -1;
NextCh();
}
delete oldBuf;
oldBuf = nullptr;
#endif
pt = tokens = CreateToken(); // first token is a dummy
}UsVal UsCtx::StringLiteral(UtScriptLanguage::Token* t)
{
std::string str(t->val + 1, t->val + t->len - 1);
std::string unescapedStr;
bool hasSlash = false;
// 使用UTF-8安全的字符迭代
for (size_t i = 0; i < str.length(); ++i)
{
unsigned char c = static_cast<unsigned char>(str[i]);
if (!hasSlash)
{
if (c == '\\')
{
hasSlash = true;
}
else
{
// 检查是否是UTF-8多字节字符的开始
if (c >= 0x80) // UTF-8多字节字符
{
// 计算UTF-8字符的字节数
size_t utf8_len = 1;
if ((c & 0xE0) == 0xC0) utf8_len = 2; // 110xxxxx
else if ((c & 0xF0) == 0xE0) utf8_len = 3; // 1110xxxx
else if ((c & 0xF8) == 0xF0) utf8_len = 4; // 11110xxx
// 确保不会越界,并复制完整的UTF-8字符
if (i + utf8_len <= str.length())
{
unescapedStr.append(str, i, utf8_len);
i += utf8_len - 1; // -1因为for循环会++i
}
else
{
// 如果UTF-8字符不完整,按原样添加
unescapedStr += c;
}
}
else
{
// ASCII字符,直接添加
unescapedStr += c;
}
}
}
else
{
switch (c)
{
case 'a':
unescapedStr += '\a';
break;
case 'b':
unescapedStr += '\b';
break;
case 'r':
unescapedStr += '\r';
break;
case 'f':
unescapedStr += '\f';
break;
case 'n':
unescapedStr += '\n';
break;
case 't':
unescapedStr += '\t';
break;
case 'v':
unescapedStr += '\v';
break;
case '\'':
case '"':
case '\\':
unescapedStr += c;
break;
default:
// 对于不认识的转义序列,保留反斜杠和字符
unescapedStr += '\\';
unescapedStr += c;
break;
}
hasSlash = false;
}
}
return CreateData(unescapedStr);
}{
StatType fileType(cSTAT_ERROR);
std::string sysPath = GetSystemPath();
#ifdef _WIN32
// 使用Unicode版本的文件检查
if (UtPathUnicode::FileExists(mPathString))
{
fileType = cFILE;
}
else if (UtPathUnicode::DirectoryExists(mPathString))
{
fileType = cDIRECTORY;
}
#else
struct stat buff;
if (0 == ::stat(sysPath.c_str(), &buff))
{
if ((buff.st_mode & S_IFDIR) != 0)
{
fileType = cDIRECTORY;
}
else
{
fileType = cFILE;
}
}
#endif
return fileType;
}//
// CUI
//
// The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
//
// Copyright 2003-2015 The Boeing Company. All rights reserved.
//
// The use, dissemination or disclosure of data in this file is subject to
// limitation or restriction. See accompanying README and LICENSE for details.
//
#include "UtPathUnicode.hpp"
#include <sys/stat.h>
#ifdef _WIN32
#include <io.h>
#include <direct.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#endif
#ifdef _WIN32
std::wstring UtPathUnicode::Utf8ToWide(const std::string& aUtf8)
{
if (aUtf8.empty())
return std::wstring();
int wideSize = MultiByteToWideChar(CP_UTF8, 0, aUtf8.c_str(), -1, nullptr, 0);
if (wideSize <= 0)
return std::wstring();
std::wstring wide(wideSize - 1, 0);
MultiByteToWideChar(CP_UTF8, 0, aUtf8.c_str(), -1, &wide[0], wideSize);
return wide;
}
std::string UtPathUnicode::WideToUtf8(const std::wstring& aWide)
{
if (aWide.empty())
return std::string();
int utf8Size = WideCharToMultiByte(CP_UTF8, 0, aWide.c_str(), -1, nullptr, 0, nullptr, nullptr);
if (utf8Size <= 0)
return std::string();
std::string utf8(utf8Size - 1, 0);
WideCharToMultiByte(CP_UTF8, 0, aWide.c_str(), -1, &utf8[0], utf8Size, nullptr, nullptr);
return utf8;
}
std::string UtPathUnicode::AnsiToUtf8(const std::string& aAnsi)
{
if (aAnsi.empty())
return std::string();
// 先转换为宽字符
int wideSize = MultiByteToWideChar(CP_ACP, 0, aAnsi.c_str(), -1, nullptr, 0);
if (wideSize <= 0)
return aAnsi;
std::wstring wide(wideSize - 1, 0);
MultiByteToWideChar(CP_ACP, 0, aAnsi.c_str(), -1, &wide[0], wideSize);
// 再转换为UTF-8
return WideToUtf8(wide);
}
#endif
std::string UtPathUnicode::ToSystemPath(const std::string& aUtf8Path)
{
#ifdef _WIN32
// 在Windows上,将UTF-8路径转换为系统路径
// 对于文件系统操作,我们需要使用宽字符API
return aUtf8Path; // 保持UTF-8格式,在具体的文件操作中转换
#else
// 在Unix系统上,文件系统通常使用UTF-8
return aUtf8Path;
#endif
}
std::string UtPathUnicode::FromSystemPath(const std::string& aSystemPath)
{
#ifdef _WIN32
// 假设系统路径可能是ANSI编码,转换为UTF-8
return AnsiToUtf8(aSystemPath);
#else
return aSystemPath;
#endif
}
bool UtPathUnicode::FileExists(const std::string& aUtf8Path)
{
#ifdef _WIN32
std::wstring widePath = Utf8ToWide(aUtf8Path);
DWORD attributes = GetFileAttributesW(widePath.c_str());
return (attributes != INVALID_FILE_ATTRIBUTES) &&
!(attributes & FILE_ATTRIBUTE_DIRECTORY);
#else
struct stat buffer;
return (stat(aUtf8Path.c_str(), &buffer) == 0) && S_ISREG(buffer.st_mode);
#endif
}
bool UtPathUnicode::DirectoryExists(const std::string& aUtf8Path)
{
#ifdef _WIN32
std::wstring widePath = Utf8ToWide(aUtf8Path);
DWORD attributes = GetFileAttributesW(widePath.c_str());
return (attributes != INVALID_FILE_ATTRIBUTES) &&
(attributes & FILE_ATTRIBUTE_DIRECTORY);
#else
struct stat buffer;
return (stat(aUtf8Path.c_str(), &buffer) == 0) && S_ISDIR(buffer.st_mode);
#endif
}
bool UtPathUnicode::CreateDirectory(const std::string& aUtf8Path)
{
#ifdef _WIN32
std::wstring widePath = Utf8ToWide(aUtf8Path);
return CreateDirectoryW(widePath.c_str(), nullptr) != 0;
#else
return mkdir(aUtf8Path.c_str(), 0755) == 0;
#endif
}
bool UtPathUnicode::DeleteFile(const std::string& aUtf8Path)
{
#ifdef _WIN32
std::wstring widePath = Utf8ToWide(aUtf8Path);
return DeleteFileW(widePath.c_str()) != 0;
#else
return unlink(aUtf8Path.c_str()) == 0;
#endif
}
size_t UtPathUnicode::GetFileSize(const std::string& aUtf8Path)
{
#ifdef _WIN32
std::wstring widePath = Utf8ToWide(aUtf8Path);
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
if (GetFileAttributesExW(widePath.c_str(), GetFileExInfoStandard, &fileInfo))
{
LARGE_INTEGER size;
size.HighPart = fileInfo.nFileSizeHigh;
size.LowPart = fileInfo.nFileSizeLow;
return static_cast<size_t>(size.QuadPart);
}
return 0;
#else
struct stat buffer;
if (stat(aUtf8Path.c_str(), &buffer) == 0)
{
return static_cast<size_t>(buffer.st_size);
}
return 0;
#endif
} 这些代码是为了在QPlainTextEdit中支持中文进行的所有修改,但是目前高亮和自动补全有问题,提供的文件是高亮和自动补全的cpp实现,请协助我修改代码,给出每个需要修改的函数的完整实现,不要省略不需要修改的代码