<commit_before>/*
cmdline.cpp

 ப

*/

/* Revision: 1.00 25.06.2000 $ */

/*
Modify:
  25.06.2000 SVS
    ! ⮢ Master Copy
    ! 뤥  ⢥ ᠬ⥫쭮
*/

#include "headers.hpp"
#pragma hdrstop

/* $ 30.06.2000 IS
   ⠭
*/
#include "internalheaders.hpp"
/* IS $ */

CommandLine::CommandLine()
{
  *CurDir=0;
  CmdStr.SetEditBeyondEnd(FALSE);
  LastCmdPartLength=-1;
  *LastCmdStr=0;
}

void CommandLine::DisplayObject()
{
  char TruncDir[NM];
  GetPrompt(TruncDir);
  TruncPathStr(TruncDir,(X2-X1)/2);
  GotoXY(X1,Y1);
  SetColor(COL_COMMANDLINE);
  Text(TruncDir);
  CmdStr.SetObjectColor(COL_COMMANDLINE,COL_COMMANDLINESELECTED);
  CmdStr.SetLeftPos(0);
  CmdStr.SetPosition(X1+strlen(TruncDir),Y1,X2,Y2);
  CmdStr.Show();
}

void CommandLine::SetCurPos(int Pos)
{
  CmdStr.SetLeftPos(0);
  CmdStr.SetCurPos(Pos);
  CmdStr.Redraw();
}

int CommandLine::ProcessKey(int Key)
{
  char Str[512];

  if (Key==KEY_CTRLEND && CmdStr.GetCurPos()==CmdStr.GetLength())
  {
    char Command[1024];
    if (LastCmdPartLength==-1)
      strncpy(LastCmdStr,CmdStr.GetStringAddr(),sizeof(LastCmdStr));
    strcpy(Command,LastCmdStr);
    int CurCmdPartLength=strlen(Command);
    CtrlObject->CmdHistory->GetSimilar(Command,LastCmdPartLength);
    if (LastCmdPartLength==-1)
    {
      LastCmdPartLength=CurCmdPartLength;
      strncpy(LastCmdStr,CmdStr.GetStringAddr(),sizeof(LastCmdStr));
    }
    CmdStr.SetString(Command);
    Show();
    return(TRUE);
  }

  switch(Key)
  {
    case KEY_UP:
      if (CtrlObject->LeftPanel->IsVisible() || CtrlObject->RightPanel->IsVisible())
        return(FALSE);
    case KEY_CTRLE:
      {
        char Str[1024];
        CtrlObject->CmdHistory->GetPrev(Str);
        CmdStr.SetString(Str);
        CmdStr.SetLeftPos(0);
        CmdStr.Show();
      }
      LastCmdPartLength=-1;
      return(TRUE);
    case KEY_DOWN:
      if (CtrlObject->LeftPanel->IsVisible() || CtrlObject->RightPanel->IsVisible())
        return(FALSE);
    case KEY_CTRLX:
      {
        char Str[1024];
        CtrlObject->CmdHistory->GetNext(Str);
        CmdStr.SetString(Str);
        CmdStr.SetLeftPos(0);
        CmdStr.Show();
      }
      LastCmdPartLength=-1;
      return(TRUE);
    case KEY_F2:
      ProcessUserMenu(0);
      return(TRUE);
    case KEY_ALTF8:
      {
        char Str[1024];
        int Type;
        switch(CtrlObject->CmdHistory->Select(MSG(MHistoryTitle),"History",Str,Type))
        {
          case 1:
            ExecString(Str,FALSE,FALSE);
            CtrlObject->CmdHistory->AddToHistory(Str);
            break;
          case 2:
            ExecString(Str,FALSE,TRUE);
            CtrlObject->CmdHistory->AddToHistory(Str);
            break;
          case 3:
            SetString(Str);
            break;
        }
      }
      return(TRUE);
    case KEY_SHIFTF9:
      SaveConfig(1);
      return(TRUE);
    case KEY_F10:
      CtrlObject->ExitMainLoop(TRUE);
      return(TRUE);
    case KEY_ALTF10:
      {
        char NewFolder[NM];
        {
          FolderTree Tree(NewFolder,MODALTREE_ACTIVE,4,2,ScrX-4,ScrY-4);
        }
        if (*NewFolder)
        {
          Panel *ActivePanel=CtrlObject->ActivePanel;
          ActivePanel->SetCurDir(NewFolder,TRUE);
          ActivePanel->Show();
          if (ActivePanel->GetType()==TREE_PANEL)
            ActivePanel->ProcessKey(KEY_ENTER);
        }
      }
      return(TRUE);
    case KEY_F11:
      CtrlObject->Plugins.CommandsMenu(FALSE,FALSE,0);
      return(TRUE);
    case KEY_ALTF11:
      {
        char Str[1024],ItemTitle[256];
        int Type,SelectType;
        if ((SelectType=CtrlObject->ViewHistory->Select(MSG(MViewHistoryTitle),"CmdMenu",Str,Type,ItemTitle))==1 || SelectType==2)
        {
          if (SelectType!=2)
            CtrlObject->ViewHistory->AddToHistory(Str,ItemTitle,Type);
          CtrlObject->ViewHistory->SetAddMode(FALSE,1,TRUE);

          switch(Type)
          {
            case 0:
            {
              FileViewer *ShellViewer=new FileViewer(Str,TRUE);
              CtrlObject->ModalManager.AddModal(ShellViewer);
              break;
            }
            case 1:
            {
              FileEditor *ShellEditor=new FileEditor(Str,FALSE,TRUE);
              CtrlObject->ModalManager.AddModal(ShellEditor);
              break;
            }
            case 2:
            case 3:
            {
              if (*Str!='@')
                ExecString(Str,Type-2);
              else
              {
                SaveScreen SaveScr;
                CtrlObject->LeftPanel->CloseFile();
                CtrlObject->RightPanel->CloseFile();
                Execute(Str+1,Type-2);
              }
              break;
            }
          }
          CtrlObject->ViewHistory->SetAddMode(TRUE,1,TRUE);
        }
        else
          if (SelectType==3)
            SetString(Str);
      }
      return(TRUE);
    case KEY_F12:
      CtrlObject->ModalManager.SelectModal();
      CtrlObject->ModalManager.NextModal(0);
      return(TRUE);
    case KEY_ALTF12:
      {
        char Str[1024];
        int Type,SelectType;
        if ((SelectType=CtrlObject->FolderHistory->Select(MSG(MFolderHistoryTitle),"CmdMenu",Str,Type))==1 || SelectType==2)
        {
          if (SelectType==2)
            CtrlObject->FolderHistory->SetAddMode(FALSE,2,TRUE);
          CtrlObject->ActivePanel->SetCurDir(Str,Type==0 ? TRUE:FALSE);
          CtrlObject->ActivePanel->Redraw();
          CtrlObject->FolderHistory->SetAddMode(TRUE,2,TRUE);
        }
        else
          if (SelectType==3)
            SetString(Str);
      }
      return(TRUE);
    case KEY_ENTER:
    case KEY_SHIFTENTER:
      {
        Panel *ActivePanel=CtrlObject->ActivePanel;
        CmdStr.GetString(Str,sizeof(Str));
        if (*Str==0)
          break;
        ActivePanel->SetCurPath();
        CtrlObject->CmdHistory->AddToHistory(Str);
        if (!ActivePanel->ProcessPluginEvent(FE_COMMAND,(void *)Str))
          CmdExecute(Str,FALSE,Key==KEY_SHIFTENTER,FALSE);
      }
      return(TRUE);
    case KEY_ESC:
      CmdStr.SetString("");
      CmdStr.SetLeftPos(0);
      CmdStr.Show();
      LastCmdPartLength=-1;
      return(TRUE);
    default:
      if (!CmdStr.ProcessKey(Key))
        break;
      LastCmdPartLength=-1;
      return(TRUE);
  }
  return(FALSE);
}

void CommandLine::SetCurDir(char *CurDir)
{
  strcpy(CommandLine::CurDir,CurDir);
}

void CommandLine::GetCurDir(char *CurDir)
{
  strcpy(CurDir,CommandLine::CurDir);
}

int CommandLine::CmdExecute(char *CmdLine,int AlwaysWaitFinish,
                            int SeparateWindow,int DirectRun)
{
  LastCmdPartLength=-1;
  if (!SeparateWindow && CtrlObject->Plugins.ProcessCommandLine(CmdLine))
  {
    CmdStr.SetString("");
    GotoXY(X1,Y1);
    mprintf("%*s",X2-X1+1,"");
    Show();
    ScrBuf.Flush();
    return(-1);
  }
  int Code;
  {
    RedrawDesktop Redraw;
    CtrlObject->LeftPanel->CloseChangeNotification();
    CtrlObject->RightPanel->CloseChangeNotification();
    CtrlObject->LeftPanel->CloseFile();
    CtrlObject->RightPanel->CloseFile();

    ScrollScreen(1);
    MoveCursor(X1,Y1);
    if (CurDir[0] && CurDir[1]==':')
      chdir(CurDir);
    CmdStr.SetString("");
    if (ProcessOSCommands(CmdLine))
      Code=-1;
    else
      Code=Execute(CmdLine,AlwaysWaitFinish,SeparateWindow,DirectRun);
    int CurX,CurY;
    GetCursorPos(CurX,CurY);
    if (CurY>=Y1-1)
      ScrollScreen(Min(CurY-Y1+2,Opt.ShowKeyBar ? 2:1));
    CtrlObject->LeftPanel->Update(UPDATE_KEEP_SELECTION);
    CtrlObject->RightPanel->Update(UPDATE_KEEP_SELECTION);
    GotoXY(X1,Y1);
    mprintf("%*s",X2-X1+1,"");
  }
  ScrBuf.Flush();
  return(Code);
}

int CommandLine::ProcessOSCommands(char *CmdLine)
{
  Panel *SetPanel;
  int Length;
  SetPanel=CtrlObject->ActivePanel;
  if (SetPanel->GetType()!=FILE_PANEL && CtrlObject->GetAnotherPanel(SetPanel)->GetType()==FILE_PANEL)
    SetPanel=CtrlObject->GetAnotherPanel(SetPanel);
  RemoveTrailingSpaces(CmdLine);
  if (isalpha(CmdLine[0]) && CmdLine[1]==':' && CmdLine[2]==0)
  {
    int NewDisk=toupper(CmdLine[0])-'A';
    setdisk(NewDisk);
    if (getdisk()!=NewDisk)
    {
      char NewDir[10];
      sprintf(NewDir,"%c:\\",NewDisk+'A');
      chdir(NewDir);
      setdisk(NewDisk);
    }
    SetPanel->ChangeDirToCurrent();
    return(TRUE);
  }
  if (strnicmp(CmdLine,"SET ",4)==0)
  {
    char Cmd[1024];
    strcpy(Cmd,CmdLine+4);
    char *Value=strchr(Cmd,'=');
    if (Value==NULL)
      return(FALSE);
    *Value=0;
    if (Value[1]==0)
      SetEnvironmentVariable(Cmd,NULL);
    else
    {
      char ExpandedStr[8192];
      if (ExpandEnvironmentStrings(Value+1,ExpandedStr,sizeof(ExpandedStr))!=0)
        SetEnvironmentVariable(Cmd,ExpandedStr);
    }
    return(TRUE);
  }
  if ((strnicmp(CmdLine,"CD",Length=2)==0 || strnicmp(CmdLine,"CHDIR",Length=5)==0) &&
      (isspace(CmdLine[Length]) || CmdLine[Length]=='\\' || strcmp(CmdLine+Length,"..")==0))
  {
    int ChDir=(Length==5);
    while (isspace(CmdLine[Length]))
      Length++;
    if (CmdLine[Length]=='\"')
      Length++;
    char NewDir[NM];
    strcpy(NewDir,&CmdLine[Length]);

    if (CtrlObject->Plugins.ProcessCommandLine(NewDir))
    {
      CmdStr.SetString("");
      GotoXY(X1,Y1);
      mprintf("%*s",X2-X1+1,"");
      Show();
      return(TRUE);
    }

    char *ChPtr=strrchr(NewDir,'\"');
    if (ChPtr!=NULL)
      *ChPtr=0;
    if (SetPanel->GetType()==FILE_PANEL && SetPanel->GetMode()==PLUGIN_PANEL)
    {
      SetPanel->SetCurDir(NewDir,ChDir);
      return(TRUE);
    }
    char ExpandedDir[8192];
    if (ExpandEnvironmentStrings(NewDir,ExpandedDir,sizeof(ExpandedDir))!=0)
      if (chdir(ExpandedDir)==-1)
        return(FALSE);
    SetPanel->ChangeDirToCurrent();
    if (!SetPanel->IsVisible())
      SetPanel->SetTitle();
    return(TRUE);
  }
  return(FALSE);
}

void CommandLine::GetString(char *Str,int MaxSize)
{
  CmdStr.GetString(Str,MaxSize);
}

void CommandLine::SetString(char *Str)
{
  LastCmdPartLength=-1;
  CmdStr.SetString(Str);
  CmdStr.SetLeftPos(0);
  CmdStr.Show();
}

void CommandLine::ExecString(char *Str,int AlwaysWaitFinish,int SeparateWindow,
                             int DirectRun)
{
  SetString(Str);
  CmdExecute(Str,AlwaysWaitFinish,SeparateWindow,DirectRun);
}

void CommandLine::InsertString(char *Str)
{
  LastCmdPartLength=-1;
  CmdStr.InsertString(Str);
  CmdStr.Show();
}

int CommandLine::ProcessMouse(MOUSE_EVENT_RECORD *MouseEvent)
{
  return(CmdStr.ProcessMouse(MouseEvent));
}

void CommandLine::GetPrompt(char *DestStr)
{
  char FormatStr[512],ExpandedFormatStr[512];
  strcpy(FormatStr,Opt.UsePromptFormat ? Opt.PromptFormat:"$p$g");
  char *Format=FormatStr;
  if (Opt.UsePromptFormat)
  {
    ExpandEnvironmentStrings(FormatStr,ExpandedFormatStr,sizeof(ExpandedFormatStr));
    Format=ExpandedFormatStr;
  }
  while (*Format)
  {
    if (*Format=='$')
    {
      Format++;
      switch(*Format)
      {
        case '$':
          *(DestStr++)='$';
          break;
        case 'p':
          strcpy(DestStr,CurDir);
          DestStr+=strlen(CurDir);
          break;
        case 'n':
          if (isalpha(CurDir[0]) && CurDir[1]==':' && CurDir[2]=='\\')
            *(DestStr++)=LocalUpper(*CurDir);
          else
            *(DestStr++)='?';
          break;
        case 'g':
          *(DestStr++)='>';
          break;
      }
      Format++;
    }
    else
      *(DestStr++)=*(Format++);
  }
  *DestStr=0;
}

int CommandLine::GetCurPos()
{
  return(CmdStr.GetCurPos());
}
<commit_msg>FAR patch 00101.cmdline Дата              : 02.08.2000 Сделал            : andrey tretjakov Описание          : очень мелкий фикс Измененные файлы  : cmdline.cpp Состав            : cmdline.txt cmdline.cpp.diff Основан на патче  : 95 Дополнение        : <commit_after>/*
cmdline.cpp

 ப

*/

/* Revision: 1.01 02.08.2000 $ */

/*
Modify:
  02.08.2000 tran 1.01
    -  䨪 -  室  CtrlF10, ᫨ 䠩    ᬮ
       Alt-F11,   keybar
       ᥣ  CtrlObject->Redraw()
  25.06.2000 SVS
    ! ⮢ Master Copy
    ! 뤥  ⢥ ᠬ⥫쭮
*/

#include "headers.hpp"
#pragma hdrstop

/* $ 30.06.2000 IS
   ⠭
*/
#include "internalheaders.hpp"
/* IS $ */

CommandLine::CommandLine()
{
  *CurDir=0;
  CmdStr.SetEditBeyondEnd(FALSE);
  LastCmdPartLength=-1;
  *LastCmdStr=0;
}

void CommandLine::DisplayObject()
{
  char TruncDir[NM];
  GetPrompt(TruncDir);
  TruncPathStr(TruncDir,(X2-X1)/2);
  GotoXY(X1,Y1);
  SetColor(COL_COMMANDLINE);
  Text(TruncDir);
  CmdStr.SetObjectColor(COL_COMMANDLINE,COL_COMMANDLINESELECTED);
  CmdStr.SetLeftPos(0);
  CmdStr.SetPosition(X1+strlen(TruncDir),Y1,X2,Y2);
  CmdStr.Show();
}

void CommandLine::SetCurPos(int Pos)
{
  CmdStr.SetLeftPos(0);
  CmdStr.SetCurPos(Pos);
  CmdStr.Redraw();
}

int CommandLine::ProcessKey(int Key)
{
  char Str[512];

  if (Key==KEY_CTRLEND && CmdStr.GetCurPos()==CmdStr.GetLength())
  {
    char Command[1024];
    if (LastCmdPartLength==-1)
      strncpy(LastCmdStr,CmdStr.GetStringAddr(),sizeof(LastCmdStr));
    strcpy(Command,LastCmdStr);
    int CurCmdPartLength=strlen(Command);
    CtrlObject->CmdHistory->GetSimilar(Command,LastCmdPartLength);
    if (LastCmdPartLength==-1)
    {
      LastCmdPartLength=CurCmdPartLength;
      strncpy(LastCmdStr,CmdStr.GetStringAddr(),sizeof(LastCmdStr));
    }
    CmdStr.SetString(Command);
    Show();
    return(TRUE);
  }

  switch(Key)
  {
    case KEY_UP:
      if (CtrlObject->LeftPanel->IsVisible() || CtrlObject->RightPanel->IsVisible())
        return(FALSE);
    case KEY_CTRLE:
      {
        char Str[1024];
        CtrlObject->CmdHistory->GetPrev(Str);
        CmdStr.SetString(Str);
        CmdStr.SetLeftPos(0);
        CmdStr.Show();
      }
      LastCmdPartLength=-1;
      return(TRUE);
    case KEY_DOWN:
      if (CtrlObject->LeftPanel->IsVisible() || CtrlObject->RightPanel->IsVisible())
        return(FALSE);
    case KEY_CTRLX:
      {
        char Str[1024];
        CtrlObject->CmdHistory->GetNext(Str);
        CmdStr.SetString(Str);
        CmdStr.SetLeftPos(0);
        CmdStr.Show();
      }
      LastCmdPartLength=-1;
      return(TRUE);
    case KEY_F2:
      ProcessUserMenu(0);
      return(TRUE);
    case KEY_ALTF8:
      {
        char Str[1024];
        int Type;
        switch(CtrlObject->CmdHistory->Select(MSG(MHistoryTitle),"History",Str,Type))
        {
          case 1:
            ExecString(Str,FALSE,FALSE);
            CtrlObject->CmdHistory->AddToHistory(Str);
            break;
          case 2:
            ExecString(Str,FALSE,TRUE);
            CtrlObject->CmdHistory->AddToHistory(Str);
            break;
          case 3:
            SetString(Str);
            break;
        }
      }
      return(TRUE);
    case KEY_SHIFTF9:
      SaveConfig(1);
      return(TRUE);
    case KEY_F10:
      CtrlObject->ExitMainLoop(TRUE);
      return(TRUE);
    case KEY_ALTF10:
      {
        char NewFolder[NM];
        {
          FolderTree Tree(NewFolder,MODALTREE_ACTIVE,4,2,ScrX-4,ScrY-4);
        }
        if (*NewFolder)
        {
          Panel *ActivePanel=CtrlObject->ActivePanel;
          ActivePanel->SetCurDir(NewFolder,TRUE);
          ActivePanel->Show();
          if (ActivePanel->GetType()==TREE_PANEL)
            ActivePanel->ProcessKey(KEY_ENTER);
        }
      }
      return(TRUE);
    case KEY_F11:
      CtrlObject->Plugins.CommandsMenu(FALSE,FALSE,0);
      return(TRUE);
    case KEY_ALTF11:
      {
        char Str[1024],ItemTitle[256];
        int Type,SelectType;
        if ((SelectType=CtrlObject->ViewHistory->Select(MSG(MViewHistoryTitle),"CmdMenu",Str,Type,ItemTitle))==1 || SelectType==2)
        {
          if (SelectType!=2)
            CtrlObject->ViewHistory->AddToHistory(Str,ItemTitle,Type);
          CtrlObject->ViewHistory->SetAddMode(FALSE,1,TRUE);

          switch(Type)
          {
            case 0:
            {
              FileViewer *ShellViewer=new FileViewer(Str,TRUE);
              CtrlObject->ModalManager.AddModal(ShellViewer);
              break;
            }
            case 1:
            {
              FileEditor *ShellEditor=new FileEditor(Str,FALSE,TRUE);
              CtrlObject->ModalManager.AddModal(ShellEditor);
              break;
            }
            case 2:
            case 3:
            {
              if (*Str!='@')
                ExecString(Str,Type-2);
              else
              {
                SaveScreen SaveScr;
                CtrlObject->LeftPanel->CloseFile();
                CtrlObject->RightPanel->CloseFile();
                Execute(Str+1,Type-2);
              }
              break;
            }
          }
          CtrlObject->ViewHistory->SetAddMode(TRUE,1,TRUE);
        }
        else
          if (SelectType==3)
            SetString(Str);
      }
      CtrlObject->Redraw();
      return(TRUE);
    case KEY_F12:
      CtrlObject->ModalManager.SelectModal();
      CtrlObject->ModalManager.NextModal(0);
      return(TRUE);
    case KEY_ALTF12:
      {
        char Str[1024];
        int Type,SelectType;
        if ((SelectType=CtrlObject->FolderHistory->Select(MSG(MFolderHistoryTitle),"CmdMenu",Str,Type))==1 || SelectType==2)
        {
          if (SelectType==2)
            CtrlObject->FolderHistory->SetAddMode(FALSE,2,TRUE);
          CtrlObject->ActivePanel->SetCurDir(Str,Type==0 ? TRUE:FALSE);
          CtrlObject->ActivePanel->Redraw();
          CtrlObject->FolderHistory->SetAddMode(TRUE,2,TRUE);
        }
        else
          if (SelectType==3)
            SetString(Str);
      }
      return(TRUE);
    case KEY_ENTER:
    case KEY_SHIFTENTER:
      {
        Panel *ActivePanel=CtrlObject->ActivePanel;
        CmdStr.GetString(Str,sizeof(Str));
        if (*Str==0)
          break;
        ActivePanel->SetCurPath();
        CtrlObject->CmdHistory->AddToHistory(Str);
        if (!ActivePanel->ProcessPluginEvent(FE_COMMAND,(void *)Str))
          CmdExecute(Str,FALSE,Key==KEY_SHIFTENTER,FALSE);
      }
      return(TRUE);
    case KEY_ESC:
      CmdStr.SetString("");
      CmdStr.SetLeftPos(0);
      CmdStr.Show();
      LastCmdPartLength=-1;
      return(TRUE);
    default:
      if (!CmdStr.ProcessKey(Key))
        break;
      LastCmdPartLength=-1;
      return(TRUE);
  }
  return(FALSE);
}

void CommandLine::SetCurDir(char *CurDir)
{
  strcpy(CommandLine::CurDir,CurDir);
}

void CommandLine::GetCurDir(char *CurDir)
{
  strcpy(CurDir,CommandLine::CurDir);
}

int CommandLine::CmdExecute(char *CmdLine,int AlwaysWaitFinish,
                            int SeparateWindow,int DirectRun)
{
  LastCmdPartLength=-1;
  if (!SeparateWindow && CtrlObject->Plugins.ProcessCommandLine(CmdLine))
  {
    CmdStr.SetString("");
    GotoXY(X1,Y1);
    mprintf("%*s",X2-X1+1,"");
    Show();
    ScrBuf.Flush();
    return(-1);
  }
  int Code;
  {
    RedrawDesktop Redraw;
    CtrlObject->LeftPanel->CloseChangeNotification();
    CtrlObject->RightPanel->CloseChangeNotification();
    CtrlObject->LeftPanel->CloseFile();
    CtrlObject->RightPanel->CloseFile();

    ScrollScreen(1);
    MoveCursor(X1,Y1);
    if (CurDir[0] && CurDir[1]==':')
      chdir(CurDir);
    CmdStr.SetString("");
    if (ProcessOSCommands(CmdLine))
      Code=-1;
    else
      Code=Execute(CmdLine,AlwaysWaitFinish,SeparateWindow,DirectRun);
    int CurX,CurY;
    GetCursorPos(CurX,CurY);
    if (CurY>=Y1-1)
      ScrollScreen(Min(CurY-Y1+2,Opt.ShowKeyBar ? 2:1));
    CtrlObject->LeftPanel->Update(UPDATE_KEEP_SELECTION);
    CtrlObject->RightPanel->Update(UPDATE_KEEP_SELECTION);
    GotoXY(X1,Y1);
    mprintf("%*s",X2-X1+1,"");
  }
  ScrBuf.Flush();
  return(Code);
}

int CommandLine::ProcessOSCommands(char *CmdLine)
{
  Panel *SetPanel;
  int Length;
  SetPanel=CtrlObject->ActivePanel;
  if (SetPanel->GetType()!=FILE_PANEL && CtrlObject->GetAnotherPanel(SetPanel)->GetType()==FILE_PANEL)
    SetPanel=CtrlObject->GetAnotherPanel(SetPanel);
  RemoveTrailingSpaces(CmdLine);
  if (isalpha(CmdLine[0]) && CmdLine[1]==':' && CmdLine[2]==0)
  {
    int NewDisk=toupper(CmdLine[0])-'A';
    setdisk(NewDisk);
    if (getdisk()!=NewDisk)
    {
      char NewDir[10];
      sprintf(NewDir,"%c:\\",NewDisk+'A');
      chdir(NewDir);
      setdisk(NewDisk);
    }
    SetPanel->ChangeDirToCurrent();
    return(TRUE);
  }
  if (strnicmp(CmdLine,"SET ",4)==0)
  {
    char Cmd[1024];
    strcpy(Cmd,CmdLine+4);
    char *Value=strchr(Cmd,'=');
    if (Value==NULL)
      return(FALSE);
    *Value=0;
    if (Value[1]==0)
      SetEnvironmentVariable(Cmd,NULL);
    else
    {
      char ExpandedStr[8192];
      if (ExpandEnvironmentStrings(Value+1,ExpandedStr,sizeof(ExpandedStr))!=0)
        SetEnvironmentVariable(Cmd,ExpandedStr);
    }
    return(TRUE);
  }
  if ((strnicmp(CmdLine,"CD",Length=2)==0 || strnicmp(CmdLine,"CHDIR",Length=5)==0) &&
      (isspace(CmdLine[Length]) || CmdLine[Length]=='\\' || strcmp(CmdLine+Length,"..")==0))
  {
    int ChDir=(Length==5);
    while (isspace(CmdLine[Length]))
      Length++;
    if (CmdLine[Length]=='\"')
      Length++;
    char NewDir[NM];
    strcpy(NewDir,&CmdLine[Length]);

    if (CtrlObject->Plugins.ProcessCommandLine(NewDir))
    {
      CmdStr.SetString("");
      GotoXY(X1,Y1);
      mprintf("%*s",X2-X1+1,"");
      Show();
      return(TRUE);
    }

    char *ChPtr=strrchr(NewDir,'\"');
    if (ChPtr!=NULL)
      *ChPtr=0;
    if (SetPanel->GetType()==FILE_PANEL && SetPanel->GetMode()==PLUGIN_PANEL)
    {
      SetPanel->SetCurDir(NewDir,ChDir);
      return(TRUE);
    }
    char ExpandedDir[8192];
    if (ExpandEnvironmentStrings(NewDir,ExpandedDir,sizeof(ExpandedDir))!=0)
      if (chdir(ExpandedDir)==-1)
        return(FALSE);
    SetPanel->ChangeDirToCurrent();
    if (!SetPanel->IsVisible())
      SetPanel->SetTitle();
    return(TRUE);
  }
  return(FALSE);
}

void CommandLine::GetString(char *Str,int MaxSize)
{
  CmdStr.GetString(Str,MaxSize);
}

void CommandLine::SetString(char *Str)
{
  LastCmdPartLength=-1;
  CmdStr.SetString(Str);
  CmdStr.SetLeftPos(0);
  CmdStr.Show();
}

void CommandLine::ExecString(char *Str,int AlwaysWaitFinish,int SeparateWindow,
                             int DirectRun)
{
  SetString(Str);
  CmdExecute(Str,AlwaysWaitFinish,SeparateWindow,DirectRun);
}

void CommandLine::InsertString(char *Str)
{
  LastCmdPartLength=-1;
  CmdStr.InsertString(Str);
  CmdStr.Show();
}

int CommandLine::ProcessMouse(MOUSE_EVENT_RECORD *MouseEvent)
{
  return(CmdStr.ProcessMouse(MouseEvent));
}

void CommandLine::GetPrompt(char *DestStr)
{
  char FormatStr[512],ExpandedFormatStr[512];
  strcpy(FormatStr,Opt.UsePromptFormat ? Opt.PromptFormat:"$p$g");
  char *Format=FormatStr;
  if (Opt.UsePromptFormat)
  {
    ExpandEnvironmentStrings(FormatStr,ExpandedFormatStr,sizeof(ExpandedFormatStr));
    Format=ExpandedFormatStr;
  }
  while (*Format)
  {
    if (*Format=='$')
    {
      Format++;
      switch(*Format)
      {
        case '$':
          *(DestStr++)='$';
          break;
        case 'p':
          strcpy(DestStr,CurDir);
          DestStr+=strlen(CurDir);
          break;
        case 'n':
          if (isalpha(CurDir[0]) && CurDir[1]==':' && CurDir[2]=='\\')
            *(DestStr++)=LocalUpper(*CurDir);
          else
            *(DestStr++)='?';
          break;
        case 'g':
          *(DestStr++)='>';
          break;
      }
      Format++;
    }
    else
      *(DestStr++)=*(Format++);
  }
  *DestStr=0;
}

int CommandLine::GetCurPos()
{
  return(CmdStr.GetCurPos());
}
<|endoftext|>


<commit_before>// -----------------------------------------------------------------
// libpion: a C++ framework for building lightweight HTTP interfaces
// -----------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt
//

#if defined(PION_HAVE_LOG4CXX)
	#include <log4cxx/spi/loggingevent.h>
	#include <boost/lexical_cast.hpp>
#elif defined(PION_HAVE_LOG4CPLUS)
	#include <log4cplus/spi/loggingevent.h>
	#include <boost/lexical_cast.hpp>
#elif defined(PION_HAVE_LOG4CPP)
	#include <log4cpp/BasicLayout.hh>
#endif

#include "LogModule.hpp"
#include <libpion/HTTPResponse.hpp>

using namespace pion;

// static members of LogModuleAppender

const unsigned int		LogModuleAppender::DEFAULT_MAX_EVENTS = 25;

// LogModuleAppender member functions

#if defined(PION_HAVE_LOG4CPP)
LogModuleAppender::LogModuleAppender(void)
	: log4cpp::AppenderSkeleton("LogModuleAppender"),
	m_max_events(DEFAULT_MAX_EVENTS), m_num_events(0),
	m_layout_ptr(new log4cpp::BasicLayout())
	{}
#else
LogModuleAppender::LogModuleAppender(void)
	: m_max_events(DEFAULT_MAX_EVENTS), m_num_events(0)
	{}
#endif

#if defined(PION_HAVE_LOG4CXX)
void LogModuleAppender::append(const log4cxx::spi::LoggingEventPtr& event)
{
	// custom layouts is not supported for log4cxx library
	std::string formatted_string(boost::lexical_cast<std::string>(event->getTimeStamp()));
	formatted_string += ' ';
	formatted_string += event->getLevel()->toString();
	formatted_string += ' ';
	formatted_string += event->getLoggerName();
	formatted_string += " - ";
	formatted_string += event->getRenderedMessage();
	formatted_string += '\n';
	addLogString(formatted_string);
}
#elif defined(PION_HAVE_LOG4CPLUS)
void LogModuleAppender::append(const log4cplus::spi::InternalLoggingEvent& event)
{
	// custom layouts is not supported for log4cplus library
	std::string formatted_string(boost::lexical_cast<std::string>(event.getTimestamp().sec()));
	formatted_string += ' ';
	formatted_string += m_log_level_manager.toString(event.getLogLevel());
	formatted_string += ' ';
	formatted_string += event.getLoggerName();
	formatted_string += " - ";
	formatted_string += event.getMessage();
	formatted_string += '\n';
	addLogString(formatted_string);
}
#elif defined(PION_HAVE_LOG4CPP)
void LogModuleAppender::_append(const log4cpp::LoggingEvent& event)
{
	std::string formatted_string(m_layout_ptr->format(event));
	addLogString(formatted_string);
}
#endif

void LogModuleAppender::addLogString(const std::string& log_string)
{
	boost::mutex::scoped_lock log_lock(m_log_mutex);
	m_log_events.push_back(log_string);
	++m_num_events;
	while (m_num_events > m_max_events) {
		m_log_events.erase(m_log_events.begin());
		--m_num_events;
	}
}

void LogModuleAppender::writeLogEvents(pion::HTTPResponsePtr& response)
{
#if defined(PION_HAVE_LOG4CXX) || defined(PION_HAVE_LOG4CPLUS) || defined(PION_HAVE_LOG4CPP)
	boost::mutex::scoped_lock log_lock(m_log_mutex);
	for (std::list<std::string>::const_iterator i = m_log_events.begin();
		 i != m_log_events.end(); ++i)
	{
		response << *i;
	}
#else
	response << "Logging is disabled." << HTTPTypes::STRING_CRLF;
#endif
}

// LogModule member functions

LogModule::LogModule(void)
	: m_log_appender_ptr(new LogModuleAppender())
{
#if defined(PION_HAVE_LOG4CXX)
	m_log_appender_ptr->setName("LogModuleAppender");
	log4cxx::Logger::getRootLogger()->addAppender(m_log_appender_ptr);
#elif defined(PION_HAVE_LOG4CPLUS)
	m_log_appender_ptr->setName("LogModuleAppender");
	log4cplus::Logger::getRoot().addAppender(m_log_appender_ptr);
#elif defined(PION_HAVE_LOG4CPP)
	log4cpp::Category::getRoot().addAppender(m_log_appender_ptr);
#endif
}

LogModule::~LogModule()
{
#if defined(PION_HAVE_LOG4CXX)
	// removeAppender() also deletes the object
	log4cxx::Logger::getRootLogger()->removeAppender(m_log_appender_ptr);
#elif defined(PION_HAVE_LOG4CPLUS)
	// removeAppender() also deletes the object
	log4cplus::Logger::getRoot().removeAppender("LogModuleAppender");
#elif defined(PION_HAVE_LOG4CPP)
	// removeAppender() also deletes the object
	log4cpp::Category::getRoot().removeAppender(m_log_appender_ptr);
#else
	delete m_log_appender_ptr;
#endif
}

/// handles requests for LogModule
bool LogModule::handleRequest(HTTPRequestPtr& request, TCPConnectionPtr& tcp_conn)
{
	// Set Content-type to "text/plain" (plain ascii text)
	HTTPResponsePtr response(HTTPResponse::create());
	response->setContentType(HTTPTypes::CONTENT_TYPE_TEXT);
	getLogAppender().writeLogEvents(response);
	response->send(tcp_conn);
	return true;
}

/// creates new LogModule objects
extern "C" PION_PLUGIN_API LogModule *pion_create_LogModule(void)
{
	return new LogModule();
}

/// destroys LogModule objects
extern "C" PION_PLUGIN_API void pion_destroy_LogModule(LogModule *module_ptr)
{
	delete module_ptr;
}
<commit_msg>http://trac.atomiclabs.com/libpion/ticket/31 Fixed log4cxx support - moving around headers screwed things up<commit_after>// -----------------------------------------------------------------
// libpion: a C++ framework for building lightweight HTTP interfaces
// -----------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt
//

#include "LogModule.hpp"

#if defined(PION_HAVE_LOG4CXX)
	#include <log4cxx/spi/loggingevent.h>
	#include <boost/lexical_cast.hpp>
#elif defined(PION_HAVE_LOG4CPLUS)
	#include <log4cplus/spi/loggingevent.h>
	#include <boost/lexical_cast.hpp>
#elif defined(PION_HAVE_LOG4CPP)
	#include <log4cpp/BasicLayout.hh>
#endif

#include <libpion/HTTPResponse.hpp>

using namespace pion;

// static members of LogModuleAppender

const unsigned int		LogModuleAppender::DEFAULT_MAX_EVENTS = 25;

// LogModuleAppender member functions

#if defined(PION_HAVE_LOG4CPP)
LogModuleAppender::LogModuleAppender(void)
	: log4cpp::AppenderSkeleton("LogModuleAppender"),
	m_max_events(DEFAULT_MAX_EVENTS), m_num_events(0),
	m_layout_ptr(new log4cpp::BasicLayout())
	{}
#else
LogModuleAppender::LogModuleAppender(void)
	: m_max_events(DEFAULT_MAX_EVENTS), m_num_events(0)
	{}
#endif

#if defined(PION_HAVE_LOG4CXX)
void LogModuleAppender::append(const log4cxx::spi::LoggingEventPtr& event)
{
	// custom layouts is not supported for log4cxx library
	std::string formatted_string(boost::lexical_cast<std::string>(event->getTimeStamp()));
	formatted_string += ' ';
	formatted_string += event->getLevel()->toString();
	formatted_string += ' ';
	formatted_string += event->getLoggerName();
	formatted_string += " - ";
	formatted_string += event->getRenderedMessage();
	formatted_string += '\n';
	addLogString(formatted_string);
}
#elif defined(PION_HAVE_LOG4CPLUS)
void LogModuleAppender::append(const log4cplus::spi::InternalLoggingEvent& event)
{
	// custom layouts is not supported for log4cplus library
	std::string formatted_string(boost::lexical_cast<std::string>(event.getTimestamp().sec()));
	formatted_string += ' ';
	formatted_string += m_log_level_manager.toString(event.getLogLevel());
	formatted_string += ' ';
	formatted_string += event.getLoggerName();
	formatted_string += " - ";
	formatted_string += event.getMessage();
	formatted_string += '\n';
	addLogString(formatted_string);
}
#elif defined(PION_HAVE_LOG4CPP)
void LogModuleAppender::_append(const log4cpp::LoggingEvent& event)
{
	std::string formatted_string(m_layout_ptr->format(event));
	addLogString(formatted_string);
}
#endif

void LogModuleAppender::addLogString(const std::string& log_string)
{
	boost::mutex::scoped_lock log_lock(m_log_mutex);
	m_log_events.push_back(log_string);
	++m_num_events;
	while (m_num_events > m_max_events) {
		m_log_events.erase(m_log_events.begin());
		--m_num_events;
	}
}

void LogModuleAppender::writeLogEvents(pion::HTTPResponsePtr& response)
{
#if defined(PION_HAVE_LOG4CXX) || defined(PION_HAVE_LOG4CPLUS) || defined(PION_HAVE_LOG4CPP)
	boost::mutex::scoped_lock log_lock(m_log_mutex);
	for (std::list<std::string>::const_iterator i = m_log_events.begin();
		 i != m_log_events.end(); ++i)
	{
		response << *i;
	}
#else
	response << "Logging is disabled." << HTTPTypes::STRING_CRLF;
#endif
}

// LogModule member functions

LogModule::LogModule(void)
	: m_log_appender_ptr(new LogModuleAppender())
{
#if defined(PION_HAVE_LOG4CXX)
	m_log_appender_ptr->setName("LogModuleAppender");
	log4cxx::Logger::getRootLogger()->addAppender(m_log_appender_ptr);
#elif defined(PION_HAVE_LOG4CPLUS)
	m_log_appender_ptr->setName("LogModuleAppender");
	log4cplus::Logger::getRoot().addAppender(m_log_appender_ptr);
#elif defined(PION_HAVE_LOG4CPP)
	log4cpp::Category::getRoot().addAppender(m_log_appender_ptr);
#endif
}

LogModule::~LogModule()
{
#if defined(PION_HAVE_LOG4CXX)
	// removeAppender() also deletes the object
	log4cxx::Logger::getRootLogger()->removeAppender(m_log_appender_ptr);
#elif defined(PION_HAVE_LOG4CPLUS)
	// removeAppender() also deletes the object
	log4cplus::Logger::getRoot().removeAppender("LogModuleAppender");
#elif defined(PION_HAVE_LOG4CPP)
	// removeAppender() also deletes the object
	log4cpp::Category::getRoot().removeAppender(m_log_appender_ptr);
#else
	delete m_log_appender_ptr;
#endif
}

/// handles requests for LogModule
bool LogModule::handleRequest(HTTPRequestPtr& request, TCPConnectionPtr& tcp_conn)
{
	// Set Content-type to "text/plain" (plain ascii text)
	HTTPResponsePtr response(HTTPResponse::create());
	response->setContentType(HTTPTypes::CONTENT_TYPE_TEXT);
	getLogAppender().writeLogEvents(response);
	response->send(tcp_conn);
	return true;
}

/// creates new LogModule objects
extern "C" PION_PLUGIN_API LogModule *pion_create_LogModule(void)
{
	return new LogModule();
}

/// destroys LogModule objects
extern "C" PION_PLUGIN_API void pion_destroy_LogModule(LogModule *module_ptr)
{
	delete module_ptr;
}
<|endoftext|>


<commit_before>#include "Xmodem.h"

/**
 * Construct an Xmodem instance.
 *
 * @param serial port to use
 */
Xmodem::Xmodem(Stream& serial) {
#ifdef ARDUINO
  _serial = &serial;
#else
  _serial = *serial;
#endif // ifdef ARDUINO
}

/**
 * Send a file over the serial port.
 * @param file file to send
 */
int Xmodem::send(File* file) {
  _file = file;
  _packetNumber = 1;

  while (true) {
    int c = serialRead();
    if (c != -1) {
      break;
    }
    delay(100);
  }

  int status = 0;
  while (true) {
    size_t bytesRead = readPacket();
    if (bytesRead > 0) {
      status = sendPacket();
      if (status < 0) {
        break;
      }
    }
    if (bytesRead < PACKET_SIZE) {
      break;
    }
  }
  serialWrite(EOT);
  delay(1);
  serialRead();
  return status;
}

/**
 * @internal
 *
 * Send the current packet over the serial port and handle response.
 *
 *  + ACK - r
 * @return -1 if error
 */
int Xmodem::sendPacket() {
  serialWrite(STX);
  serialWrite(_packetNumber);
  serialWrite(255 - _packetNumber);
  serialWrite(_packet, PACKET_SIZE);
  serialWrite((_crc >> 8) & 0xff);
  serialWrite(_crc & 0xff);

  int c;
  while (true) {
    c = serialRead();
    if (c == NAK) {
      delay(5);
      return sendPacket();
    }
    else if (c == ACK) {
      _packetNumber++;
      return 0;
    }
    else if (c == CAN) {
      return -1;
    }
    delay(500);
  }
}

/**
 * Read current packet from current file. Pad the packet with PAD_CHAR if the
 * file has less than PACKET_SIZE bytes left to read.
 *
 * @return the number of bytes read from the file
 */
size_t Xmodem::readPacket() {
  size_t bytesRead = fileRead(_packet, PACKET_SIZE);
  for (size_t i = bytesRead; i < PACKET_SIZE; i++) {
    _packet[i] = PAD_CHAR;
  }

  _crc = crc_init();
  _crc = crc_update(_crc, _packet, PACKET_SIZE);
  _crc = crc_finalize(_crc);

  return bytesRead;
}

/**
 * @internal
 *
 * Read a block from a file.
 *
 * @param  buffer  buffer to hold data read from file
 * @param  count   number of bytes to read from file
 * @return         number of bytes actually read
 */
size_t Xmodem::fileRead(uint8_t *buffer, size_t count) {
#ifdef ARDUINO
  return _file->read(buffer, count);
#else
  return fread(buffer, 1, count, _file);
#endif // ifdef ARDUINO
}

/**
 * @internal
 *
 * Write a block of data to the serial port.
 *
 * @param  buffer data to write
 * @param  count  number of bytes to write
 * @return        number of bytes actually written
 */
size_t Xmodem::serialWrite(uint8_t *buffer, size_t count) {
#ifdef ARDUINO
  // Serial.println("writing block");

  uint8_t *current = buffer;
  int remaining = count;
  int batchSize = 128;
  size_t written = 0;
  while (remaining > 0) {
    int currentBatchSize = min(batchSize, remaining);
    written += _serial->write(current, currentBatchSize);
    current += currentBatchSize;
    remaining -= currentBatchSize;
  }
  return written;

#else
  return write(_serial, buffer, count);
#endif // ifdef ARDUINO
}

/**
 * @internal
 *
 * Write a byte to the serial port.
 *
 * @param  c byte to write
 * @return c if byte written, or -1 if error
 */
int Xmodem::serialWrite(uint8_t c) {
#ifdef ARDUINO
  return _serial->write(c);
#else
  return write(_serial, &c, 1);
#endif // ifdef ARDUINO
}

/**
 * @internal
 *
 * Read a byte from the serial port.
 *
 * @return byte read, or -1 no data is available to read
 */
int Xmodem::serialRead() {
#ifdef ARDUINO
  return _serial->read();
#else
  uint8_t c;
  size_t bytesRead = read(_serial, &c, 1);
  if (bytesRead == 0) {
    return -1;
  }
  else {
    return (int)c;
  }
#endif // ifdef ARDUINO
}
<commit_msg>improve file transfer performance<commit_after>#include "Xmodem.h"

/**
 * Construct an Xmodem instance.
 *
 * @param serial port to use
 */
Xmodem::Xmodem(Stream& serial) {
#ifdef ARDUINO
  _serial = &serial;
#else
  _serial = *serial;
#endif // ifdef ARDUINO
}

/**
 * Send a file over the serial port.
 * @param file file to send
 */
int Xmodem::send(File* file) {
  _file = file;
  _packetNumber = 1;

  while (true) {
    int c = serialRead();
    if (c != -1) {
      break;
    }
    delay(100);
  }

  int status = 0;
  while (true) {
    size_t bytesRead = readPacket();
    if (bytesRead > 0) {
      status = sendPacket();
      if (status < 0) {
        break;
      }
    }
    if (bytesRead < PACKET_SIZE) {
      break;
    }
  }
  serialWrite(EOT);
  delay(1);
  serialRead();
  return status;
}

/**
 * @internal
 *
 * Send the current packet over the serial port and handle response.
 *
 *  + ACK - r
 * @return -1 if error
 */
int Xmodem::sendPacket() {
  serialWrite(STX);
  serialWrite(_packetNumber);
  serialWrite(255 - _packetNumber);
  serialWrite(_packet, PACKET_SIZE);
  serialWrite((_crc >> 8) & 0xff);
  serialWrite(_crc & 0xff);

  int c;
  while (true) {
    c = serialRead();
    if (c == NAK) {
      delay(5);
      return sendPacket();
    }
    else if (c == ACK) {
      _packetNumber++;
      return 0;
    }
    else if (c == CAN) {
      return -1;
    }
  }
}

/**
 * Read current packet from current file. Pad the packet with PAD_CHAR if the
 * file has less than PACKET_SIZE bytes left to read.
 *
 * @return the number of bytes read from the file
 */
size_t Xmodem::readPacket() {
  size_t bytesRead = fileRead(_packet, PACKET_SIZE);
  for (size_t i = bytesRead; i < PACKET_SIZE; i++) {
    _packet[i] = PAD_CHAR;
  }

  _crc = crc_init();
  _crc = crc_update(_crc, _packet, PACKET_SIZE);
  _crc = crc_finalize(_crc);

  return bytesRead;
}

/**
 * @internal
 *
 * Read a block from a file.
 *
 * @param  buffer  buffer to hold data read from file
 * @param  count   number of bytes to read from file
 * @return         number of bytes actually read
 */
size_t Xmodem::fileRead(uint8_t *buffer, size_t count) {
#ifdef ARDUINO
  return _file->read(buffer, count);
#else
  return fread(buffer, 1, count, _file);
#endif // ifdef ARDUINO
}

/**
 * @internal
 *
 * Write a block of data to the serial port.
 *
 * @param  buffer data to write
 * @param  count  number of bytes to write
 * @return        number of bytes actually written
 */
size_t Xmodem::serialWrite(uint8_t *buffer, size_t count) {
#ifdef ARDUINO
  // Serial.println("writing block");

  uint8_t *current = buffer;
  int remaining = count;
  int batchSize = 128;
  size_t written = 0;
  while (remaining > 0) {
    int currentBatchSize = min(batchSize, remaining);
    written += _serial->write(current, currentBatchSize);
    current += currentBatchSize;
    remaining -= currentBatchSize;
  }
  return written;

#else
  return write(_serial, buffer, count);
#endif // ifdef ARDUINO
}

/**
 * @internal
 *
 * Write a byte to the serial port.
 *
 * @param  c byte to write
 * @return c if byte written, or -1 if error
 */
int Xmodem::serialWrite(uint8_t c) {
#ifdef ARDUINO
  return _serial->write(c);
#else
  return write(_serial, &c, 1);
#endif // ifdef ARDUINO
}

/**
 * @internal
 *
 * Read a byte from the serial port.
 *
 * @return byte read, or -1 no data is available to read
 */
int Xmodem::serialRead() {
#ifdef ARDUINO
  return _serial->read();
#else
  uint8_t c;
  size_t bytesRead = read(_serial, &c, 1);
  if (bytesRead == 0) {
    return -1;
  }
  else {
    return (int)c;
  }
#endif // ifdef ARDUINO
}
<|endoftext|>


<commit_before>//https://code.google.com/p/nya-engine/

#include "tga.h"
#include "memory/memory_reader.h"
#include "memory/tmp_buffer.h"
#include "resources/resources.h"

namespace nya_formats
{

size_t tga::decode_header(const void *data,size_t size)
{
    *this=tga();

    if(!data || !size)
        return 0;

    nya_memory::memory_reader reader(data,size);

    const char id_length=reader.read<char>();
    if(!reader.skip(id_length))
        return 0;

    const char colourmaptype=reader.read<char>();
    if(colourmaptype!=0)
        return 0;

    const char datatypecode=reader.read<char>();
    const short colourmaporigin=reader.read<short>();
    if(colourmaporigin!=0)
        return 0;

    const short colourmaplength=reader.read<short>();
    if(colourmaplength!=0)
        return 0;

    const char colourmapdepth=reader.read<char>();
    if(colourmapdepth!=0)
        return 0;

    //const short x_origin=
    reader.read<short>();
    //const short y_origin=
    reader.read<short>();

    const short width=reader.read<short>();
    const short height=reader.read<short>();
    const char bitsperpixel=reader.read<char>();
    const char imagedescriptor=reader.read<char>();

    color_mode channels;
    bool rle=false;

    switch(bitsperpixel)
    {
        case 32:
            if(datatypecode==10)
                channels=bgra,rle=true;
            else if(datatypecode==2)
                channels=bgra;
            else
                return false;
        break;

        case 24:
            if(datatypecode==10)
                channels=bgr,rle=true;
            else if(datatypecode==2)
                channels=bgr;
            else
                return false;
        break;

        case 8:
            if(datatypecode==11)
                channels=greyscale,rle=true;
            else if(datatypecode==3)
                channels=greyscale;
            else
                return false;
        break;

        default:
            return 0;
    }

    const size_t color_data_size=width*height*channels;
    if(!color_data_size)
        return 0;

    this->width=width;
    this->height=height;
    this->channels=channels;
    this->rle=rle;
    this->horisontal_flip=imagedescriptor&0x10;
    this->vertical_flip=imagedescriptor&0x20;
    this->data=reader.get_data();
    this->compressed_size=reader.get_remained();
    this->uncompressed_size=color_data_size;

    return reader.get_offset();
}

size_t tga::encode_header(void *to_data,size_t to_size)
{
    if(to_size<tga_minimum_header_size)
        return 0;

    char datatypecode=0;
    char bpp=channels*8;

    datatypecode=rle?10:2;
    if(channels==1)
        ++datatypecode;

    if(!datatypecode)
        return 0;

    char *out=(char *)to_data;
    memset(out,0,tga_minimum_header_size);
    memcpy(out+2,&datatypecode,1);
    memcpy(out+12,&width,2);
    memcpy(out+14,&height,2);
    memcpy(out+16,&bpp,1);

    return tga_minimum_header_size;
}

bool tga::decode_rle(void *decoded_data)
{
    if(!decoded_data || !rle)
        return false;

    typedef unsigned char uchar;
    const uchar *cur=(uchar*)data;
    const uchar *const last=(uchar*)data+compressed_size;
    uchar *out=(uchar*)decoded_data;
    const uchar *const out_last=out+uncompressed_size;

    while(out<out_last)
    {
        if(cur>=last)
            return false;

        if(*cur & 0x80)
        {
            const uchar *to=out+(*cur++ -127)*channels;
            if(cur+channels>last || to>out_last)
                return false;

            while(out<to) memcpy(out,cur,channels),out+=channels;
            cur+=channels;
        }
        else // raw
        {
            const size_t size=(*cur++ +1)*channels;
            if(cur+size>last || out+size>out_last)
                return false;

            memcpy(out,cur,size);
            cur+=size,out+=size;
        }
    }

    return true;
}

size_t tga::encode_rle(void *to_data,size_t to_size)
{
    typedef unsigned int uint;
    typedef unsigned char uchar;

    const uchar *from=(uchar *)data;
    const uchar *from_last=from+uncompressed_size;
    uchar *to=(uchar *)to_data;
    uchar *to_last=to+to_size;

    uchar raw[128*4];
    memset(raw,0,sizeof(raw));

    int curr_line=0;
    for(int rle=1;from<from_last;from+=channels*rle,curr_line+=rle)
    {
        if(curr_line>=width)
            curr_line-=width;

        memcpy(raw,from,channels);

        rle=1;
        bool is_rle=false;
        int max_rle=128;
        if(curr_line+max_rle>width)
            max_rle=width-curr_line;

        for(const uchar *check=from+channels;check<from_last;++rle,check+=channels)
        {
            if(memcmp(raw,check,channels)!=0 || rle>=max_rle)
            {
                is_rle=rle>1;
                break;
            }
        }

        if(is_rle)
        {
            if(to+channels+1>to_last)
                return 0;

            *to++ =(128 | (rle-1));
            memcpy(to,raw,channels);
            to+=channels;
            continue;
        }

        rle = 1;
        uchar *raw_it=raw;
        for(const uchar *check=from+channels;check<from_last;++rle,check+=channels)
        {
            if((memcmp(raw_it,check,channels)!=0 && rle<max_rle) || rle<3)
            {
                memcpy(raw_it+=channels,check,channels);
                if(rle>=max_rle)
                    break;

                continue;
            }

            // check if the exit condition was the start of a repeating color
            if (memcmp(raw_it,check,channels)!=0)
                rle -= 2;

            break;
        }

        size_t raw_size=channels*rle;
        if(to+raw_size+1>to_last)
            return 0;

        *to++ =rle-1;
        memcpy(to,raw,raw_size);
        to+=raw_size;
    }

    return to-(uchar*)to_data;
}

void tga::flip_vertical(const void *from_data,void *to_data)
{
    if(!from_data || !to_data)
        return;

    const int line_size=width*channels;
    const int top=line_size*(height-1);

    typedef unsigned char uchar;

    uchar *to=(uchar*)to_data;

    if(from_data==to_data)
    {
        const int half=line_size*height/2;
        uchar tmp[4];

        for(int offset=0;offset<half;offset+=line_size)
        {
            uchar *ha=to+offset;
            uchar *hb=to+top-offset;

            for(int w=0;w<line_size;w+=channels)
            {
                uchar *a=ha+w;
                uchar *b=hb+w;
                memcpy(tmp,a,channels);
                memcpy(a,b,channels);
                memcpy(b,tmp,channels);
            }
        }
    }
    else
    {
        const uchar *from=(const uchar*)from_data;
        for(int offset=0;offset<uncompressed_size;offset+=line_size)
        {
            const uchar *ha=from+offset;
            uchar *hb=to+top-offset;
            memcpy(hb,ha,line_size);
        }
    }
}

void tga::flip_horisontal(const void *from_data,void *to_data)
{
    if(!from_data || !to_data)
        return;

    const int line_size=width*channels;
    const int half=line_size/2;

    typedef unsigned char uchar;

    uchar *to=(uchar*)to_data;

    if(from_data==to_data)
    {
        uchar tmp[4];

        for(int offset=0;offset<uncompressed_size;offset+=line_size)
        {
            uchar *ha=to+offset;
            uchar *hb=ha+line_size-channels;

            for(int w=0;w<half;w+=channels)
            {
                uchar *a=ha+w;
                uchar *b=hb-w;
                memcpy(tmp,a,channels);
                memcpy(a,b,channels);
                memcpy(b,tmp,channels);
            }
        }
    }
    else
    {
        const uchar *from=(const uchar*)from_data;

        for(int offset=0;offset<uncompressed_size;offset+=line_size)
        {
            const uchar *ha=from+offset;
            uchar *hb=to+offset+line_size-channels;

            for(int w=0;w<line_size;w+=channels)
            {
                const uchar *a=ha+w;
                uchar *b=hb-w;
                memcpy(b,a,channels);
            }
        }
    }
}

bool tga_file::load(const char *file_name)
{
    release();

    nya_resources::resource_data *in_data=nya_resources::get_resources_provider().access(file_name);
    if(!in_data)
    {
        printf( "unable to open texture %s\n", file_name );
        return false;
    }

    nya_memory::tmp_buffer_scoped in_buf(in_data->get_size());
    in_data->read_all(in_buf.get_data());
    m_header.decode_header(in_buf.get_data(),in_data->get_size());
    in_data->release();

    if(m_header.rle)
    {
        m_data.resize(m_header.compressed_size);
        memcpy(&m_data[0],m_header.data,m_header.compressed_size);
    }
    else
    {
        m_data.resize(m_header.uncompressed_size);
        memcpy(&m_data[0],m_header.data,m_header.uncompressed_size);
    }

    return true;
}

bool tga_file::create(int width,int height,tga::color_mode channels)
{
    release();

    if(width<0 || height<0)
        return false;

    m_header.width=width;
    m_header.height=height;
    m_header.channels=channels;

    m_data.resize(width*height*channels,0);

    return true;
}

bool tga_file::decode_rle()
{
    if(m_data.empty())
        return false;

    if(!m_header.rle)
        return false;

    m_header.data=&m_data[0];
    nya_memory::tmp_buffer_scoped buf(m_header.uncompressed_size);
    if(!m_header.decode_rle(buf.get_data()))
        return false;

    m_header.rle=false;
    m_data.resize(m_header.uncompressed_size);
    memcpy(&m_data[0],buf.get_data(),m_header.uncompressed_size);

    return true;
}

bool tga_file::encode_rle(size_t max_compressed_size)
{
    if(m_data.empty())
        return false;

    if(m_header.rle)
        return false;

    m_header.data=&m_data[0];
    nya_memory::tmp_buffer_scoped buf(max_compressed_size);
    size_t encoded_size=m_header.encode_rle(buf.get_data(),max_compressed_size);
    if(!encoded_size)
        return false;

    m_header.rle=true;
    m_header.compressed_size=encoded_size;
    m_data.resize(encoded_size);
    memcpy(&m_data[0],buf.get_data(),encoded_size);

    return true;
}

bool tga_file::save(const char *file_name)
{
    if(m_data.empty())
        return false;

    FILE *out_file=fopen( file_name, "wb" );
    if(!out_file)
    {
        printf( "unable to save texture %s\n", file_name );
        return false;
    }

    char header_buf[m_header.tga_minimum_header_size];
    size_t header_size=m_header.encode_header(header_buf,sizeof(header_buf));
    fwrite(header_buf,1,header_size,out_file);
    fwrite(&m_data[0],1,m_data.size(),out_file);

    fclose(out_file);
    return true;
}

bool tga_file::flip_horisontal()
{
    if(m_data.empty())
        return false;

    if(m_header.rle)
        return false;

    m_header.flip_horisontal(&m_data[0],&m_data[0]);
    m_header.horisontal_flip=!m_header.horisontal_flip;

    return true;
}

bool tga_file::flip_vertical()
{
    if(m_data.empty())
        return false;

    if(m_header.rle)
        return false;

    m_header.flip_vertical(&m_data[0],&m_data[0]);
    m_header.vertical_flip=!m_header.vertical_flip;

    return true;
}

}
<commit_msg>cl.exeを幸せにする<commit_after>//https://code.google.com/p/nya-engine/

#include "tga.h"
#include "memory/memory_reader.h"
#include "memory/tmp_buffer.h"
#include "resources/resources.h"

namespace nya_formats
{

size_t tga::decode_header(const void *data,size_t size)
{
    *this=tga();

    if(!data || !size)
        return 0;

    nya_memory::memory_reader reader(data,size);

    const char id_length=reader.read<char>();
    if(!reader.skip(id_length))
        return 0;

    const char colourmaptype=reader.read<char>();
    if(colourmaptype!=0)
        return 0;

    const char datatypecode=reader.read<char>();
    const short colourmaporigin=reader.read<short>();
    if(colourmaporigin!=0)
        return 0;

    const short colourmaplength=reader.read<short>();
    if(colourmaplength!=0)
        return 0;

    const char colourmapdepth=reader.read<char>();
    if(colourmapdepth!=0)
        return 0;

    //const short x_origin=
    reader.read<short>();
    //const short y_origin=
    reader.read<short>();

    const short width=reader.read<short>();
    const short height=reader.read<short>();
    const char bitsperpixel=reader.read<char>();
    const char imagedescriptor=reader.read<char>();

    color_mode channels;
    bool rle=false;

    switch(bitsperpixel)
    {
        case 32:
            if(datatypecode==10)
                channels=bgra,rle=true;
            else if(datatypecode==2)
                channels=bgra;
            else
                return false;
        break;

        case 24:
            if(datatypecode==10)
                channels=bgr,rle=true;
            else if(datatypecode==2)
                channels=bgr;
            else
                return false;
        break;

        case 8:
            if(datatypecode==11)
                channels=greyscale,rle=true;
            else if(datatypecode==3)
                channels=greyscale;
            else
                return false;
        break;

        default:
            return 0;
    }

    const size_t color_data_size=width*height*channels;
    if(!color_data_size)
        return 0;

    this->width=width;
    this->height=height;
    this->channels=channels;
    this->rle=rle;
    this->horisontal_flip=(imagedescriptor&0x10)!=0;
    this->vertical_flip=(imagedescriptor&0x20)!=0;
    this->data=reader.get_data();
    this->compressed_size=reader.get_remained();
    this->uncompressed_size=color_data_size;

    return reader.get_offset();
}

size_t tga::encode_header(void *to_data,size_t to_size)
{
    if(to_size<tga_minimum_header_size)
        return 0;

    char datatypecode=0;
    char bpp=channels*8;

    datatypecode=rle?10:2;
    if(channels==1)
        ++datatypecode;

    if(!datatypecode)
        return 0;

    char *out=(char *)to_data;
    memset(out,0,tga_minimum_header_size);
    memcpy(out+2,&datatypecode,1);
    memcpy(out+12,&width,2);
    memcpy(out+14,&height,2);
    memcpy(out+16,&bpp,1);

    return tga_minimum_header_size;
}

bool tga::decode_rle(void *decoded_data)
{
    if(!decoded_data || !rle)
        return false;

    typedef unsigned char uchar;
    const uchar *cur=(uchar*)data;
    const uchar *const last=(uchar*)data+compressed_size;
    uchar *out=(uchar*)decoded_data;
    const uchar *const out_last=out+uncompressed_size;

    while(out<out_last)
    {
        if(cur>=last)
            return false;

        if(*cur & 0x80)
        {
            const uchar *to=out+(*cur++ -127)*channels;
            if(cur+channels>last || to>out_last)
                return false;

            while(out<to) memcpy(out,cur,channels),out+=channels;
            cur+=channels;
        }
        else // raw
        {
            const size_t size=(*cur++ +1)*channels;
            if(cur+size>last || out+size>out_last)
                return false;

            memcpy(out,cur,size);
            cur+=size,out+=size;
        }
    }

    return true;
}

size_t tga::encode_rle(void *to_data,size_t to_size)
{
    typedef unsigned int uint;
    typedef unsigned char uchar;

    const uchar *from=(uchar *)data;
    const uchar *from_last=from+uncompressed_size;
    uchar *to=(uchar *)to_data;
    uchar *to_last=to+to_size;

    uchar raw[128*4];
    memset(raw,0,sizeof(raw));

    int curr_line=0;
    for(int rle=1;from<from_last;from+=channels*rle,curr_line+=rle)
    {
        if(curr_line>=width)
            curr_line-=width;

        memcpy(raw,from,channels);

        rle=1;
        bool is_rle=false;
        int max_rle=128;
        if(curr_line+max_rle>width)
            max_rle=width-curr_line;

        for(const uchar *check=from+channels;check<from_last;++rle,check+=channels)
        {
            if(memcmp(raw,check,channels)!=0 || rle>=max_rle)
            {
                is_rle=rle>1;
                break;
            }
        }

        if(is_rle)
        {
            if(to+channels+1>to_last)
                return 0;

            *to++ =(128 | (rle-1));
            memcpy(to,raw,channels);
            to+=channels;
            continue;
        }

        rle = 1;
        uchar *raw_it=raw;
        for(const uchar *check=from+channels;check<from_last;++rle,check+=channels)
        {
            if((memcmp(raw_it,check,channels)!=0 && rle<max_rle) || rle<3)
            {
                memcpy(raw_it+=channels,check,channels);
                if(rle>=max_rle)
                    break;

                continue;
            }

            // check if the exit condition was the start of a repeating color
            if (memcmp(raw_it,check,channels)!=0)
                rle -= 2;

            break;
        }

        size_t raw_size=channels*rle;
        if(to+raw_size+1>to_last)
            return 0;

        *to++ =rle-1;
        memcpy(to,raw,raw_size);
        to+=raw_size;
    }

    return to-(uchar*)to_data;
}

void tga::flip_vertical(const void *from_data,void *to_data)
{
    if(!from_data || !to_data)
        return;

    const int line_size=width*channels;
    const int top=line_size*(height-1);

    typedef unsigned char uchar;

    uchar *to=(uchar*)to_data;

    if(from_data==to_data)
    {
        const int half=line_size*height/2;
        uchar tmp[4];

        for(int offset=0;offset<half;offset+=line_size)
        {
            uchar *ha=to+offset;
            uchar *hb=to+top-offset;

            for(int w=0;w<line_size;w+=channels)
            {
                uchar *a=ha+w;
                uchar *b=hb+w;
                memcpy(tmp,a,channels);
                memcpy(a,b,channels);
                memcpy(b,tmp,channels);
            }
        }
    }
    else
    {
        const uchar *from=(const uchar*)from_data;
        for(size_t offset=0;offset<uncompressed_size;offset+=line_size)
        {
            const uchar *ha=from+offset;
            uchar *hb=to+top-offset;
            memcpy(hb,ha,line_size);
        }
    }
}

void tga::flip_horisontal(const void *from_data,void *to_data)
{
    if(!from_data || !to_data)
        return;

    const int line_size=width*channels;
    const int half=line_size/2;

    typedef unsigned char uchar;

    uchar *to=(uchar*)to_data;

    if(from_data==to_data)
    {
        uchar tmp[4];

        for(size_t offset=0;offset<uncompressed_size;offset+=line_size)
        {
            uchar *ha=to+offset;
            uchar *hb=ha+line_size-channels;

            for(int w=0;w<half;w+=channels)
            {
                uchar *a=ha+w;
                uchar *b=hb-w;
                memcpy(tmp,a,channels);
                memcpy(a,b,channels);
                memcpy(b,tmp,channels);
            }
        }
    }
    else
    {
        const uchar *from=(const uchar*)from_data;

        for(size_t offset=0;offset<uncompressed_size;offset+=line_size)
        {
            const uchar *ha=from+offset;
            uchar *hb=to+offset+line_size-channels;

            for(int w=0;w<line_size;w+=channels)
            {
                const uchar *a=ha+w;
                uchar *b=hb-w;
                memcpy(b,a,channels);
            }
        }
    }
}

bool tga_file::load(const char *file_name)
{
    release();

    nya_resources::resource_data *in_data=nya_resources::get_resources_provider().access(file_name);
    if(!in_data)
    {
        printf( "unable to open texture %s\n", file_name );
        return false;
    }

    nya_memory::tmp_buffer_scoped in_buf(in_data->get_size());
    in_data->read_all(in_buf.get_data());
    m_header.decode_header(in_buf.get_data(),in_data->get_size());
    in_data->release();

    if(m_header.rle)
    {
        m_data.resize(m_header.compressed_size);
        memcpy(&m_data[0],m_header.data,m_header.compressed_size);
    }
    else
    {
        m_data.resize(m_header.uncompressed_size);
        memcpy(&m_data[0],m_header.data,m_header.uncompressed_size);
    }

    return true;
}

bool tga_file::create(int width,int height,tga::color_mode channels)
{
    release();

    if(width<0 || height<0)
        return false;

    m_header.width=width;
    m_header.height=height;
    m_header.channels=channels;

    m_data.resize(width*height*channels,0);

    return true;
}

bool tga_file::decode_rle()
{
    if(m_data.empty())
        return false;

    if(!m_header.rle)
        return false;

    m_header.data=&m_data[0];
    nya_memory::tmp_buffer_scoped buf(m_header.uncompressed_size);
    if(!m_header.decode_rle(buf.get_data()))
        return false;

    m_header.rle=false;
    m_data.resize(m_header.uncompressed_size);
    memcpy(&m_data[0],buf.get_data(),m_header.uncompressed_size);

    return true;
}

bool tga_file::encode_rle(size_t max_compressed_size)
{
    if(m_data.empty())
        return false;

    if(m_header.rle)
        return false;

    m_header.data=&m_data[0];
    nya_memory::tmp_buffer_scoped buf(max_compressed_size);
    size_t encoded_size=m_header.encode_rle(buf.get_data(),max_compressed_size);
    if(!encoded_size)
        return false;

    m_header.rle=true;
    m_header.compressed_size=encoded_size;
    m_data.resize(encoded_size);
    memcpy(&m_data[0],buf.get_data(),encoded_size);

    return true;
}

bool tga_file::save(const char *file_name)
{
    if(m_data.empty())
        return false;

    FILE *out_file=fopen( file_name, "wb" );
    if(!out_file)
    {
        printf( "unable to save texture %s\n", file_name );
        return false;
    }

    char header_buf[m_header.tga_minimum_header_size];
    size_t header_size=m_header.encode_header(header_buf,sizeof(header_buf));
    fwrite(header_buf,1,header_size,out_file);
    fwrite(&m_data[0],1,m_data.size(),out_file);

    fclose(out_file);
    return true;
}

bool tga_file::flip_horisontal()
{
    if(m_data.empty())
        return false;

    if(m_header.rle)
        return false;

    m_header.flip_horisontal(&m_data[0],&m_data[0]);
    m_header.horisontal_flip=!m_header.horisontal_flip;

    return true;
}

bool tga_file::flip_vertical()
{
    if(m_data.empty())
        return false;

    if(m_header.rle)
        return false;

    m_header.flip_vertical(&m_data[0],&m_data[0]);
    m_header.vertical_flip=!m_header.vertical_flip;

    return true;
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/glue/theme_change_processor.h"

#include "base/logging.h"
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/theme_util.h"
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_source.h"

namespace browser_sync {

namespace {
std::string GetThemeId(Extension* current_theme) {
  if (current_theme) {
    DCHECK(current_theme->is_theme());
  }
  return current_theme ? current_theme->id() : "default/system";
}
}  // namespace

ThemeChangeProcessor::ThemeChangeProcessor(
    UnrecoverableErrorHandler* error_handler)
    : ChangeProcessor(error_handler),
      profile_(NULL) {
  DCHECK(error_handler);
}

ThemeChangeProcessor::~ThemeChangeProcessor() {}

void ThemeChangeProcessor::Observe(NotificationType type,
                                   const NotificationSource& source,
                                   const NotificationDetails& details) {
  DCHECK(running());
  DCHECK(profile_);
  Extension* extension = Details<Extension>(details).ptr();
  std::string current_or_future_theme_id =
      profile_->GetThemeProvider()->GetThemeID();
  Extension* current_theme = profile_->GetTheme();
  switch (type.value) {
    case NotificationType::BROWSER_THEME_CHANGED:
      // We pay attention to this notification only when it signifies
      // that a user changed the theme to the default/system theme, or
      // when it signifies that a user changed the theme to a custom
      // one that was already installed.  Otherwise, current_theme
      // still points to the previous theme until it gets installed
      // and loaded (and we get an EXTENSION_LOADED notification).
      LOG(INFO) << "Got BROWSER_THEME_CHANGED notification for theme "
                << GetThemeId(extension);
      DCHECK_EQ(Source<BrowserThemeProvider>(source).ptr(),
                profile_->GetThemeProvider());
      if (extension != NULL) {
        DCHECK(extension->is_theme());
        DCHECK_EQ(extension->id(), current_or_future_theme_id);
        if (!current_theme || (current_theme->id() != extension->id())) {
          return;
        }
      }
      break;
    case NotificationType::EXTENSION_LOADED:
      // We pay attention to this notification only when it signifies
      // that a theme extension has been loaded because that means
      // that the user set the current theme to a custom theme that
      // needed to be downloaded and installed and that it was
      // installed successfully.
      DCHECK_EQ(Source<Profile>(source).ptr(), profile_);
      CHECK(extension);
      if (!extension->is_theme()) {
        return;
      }
      LOG(INFO) << "Got EXTENSION_LOADED notification for theme "
                << extension->id();
      DCHECK_EQ(extension->id(), current_or_future_theme_id);
      DCHECK_EQ(extension, current_theme);
      break;
    case NotificationType::EXTENSION_UNLOADED:
      // We pay attention to this notification only when it signifies
      // that a theme extension has been unloaded because that means
      // that the user set the current theme to a custom theme and then
      // changed his mind and undid it (reverting to the previous
      // theme).
      DCHECK_EQ(Source<Profile>(source).ptr(), profile_);
      CHECK(extension);
      if (!extension->is_theme()) {
        return;
      }
      LOG(INFO) << "Got EXTENSION_UNLOADED notification for theme "
                << extension->id();
      extension = current_theme;
      break;
    default:
      LOG(DFATAL) << "Unexpected notification received: " << type.value;
      break;
  }

  DCHECK_EQ(extension, current_theme);
  if (extension) {
    DCHECK(extension->is_theme());
  }
  LOG(INFO) << "Theme changed to " << GetThemeId(extension);

  // Here, we know that a theme is being set; the theme is a custom
  // theme iff extension is non-NULL.

  sync_api::WriteTransaction trans(share_handle());
  sync_api::WriteNode node(&trans);
  if (!node.InitByClientTagLookup(syncable::THEMES,
                                  kCurrentThemeClientTag)) {
    std::string err = "Could not create node with client tag: ";
    error_handler()->OnUnrecoverableError(FROM_HERE,
                                          err + kCurrentThemeClientTag);
    return;
  }

  sync_pb::ThemeSpecifics old_theme_specifics = node.GetThemeSpecifics();
  // Make sure to base new_theme_specifics on old_theme_specifics so
  // we preserve the state of use_system_theme_by_default.
  sync_pb::ThemeSpecifics new_theme_specifics = old_theme_specifics;
  GetThemeSpecificsFromCurrentTheme(profile_, &new_theme_specifics);
  // Do a write only if something actually changed so as to guard
  // against cycles.
  if (!AreThemeSpecificsEqual(old_theme_specifics, new_theme_specifics)) {
    node.SetThemeSpecifics(new_theme_specifics);
  }
  return;
}

void ThemeChangeProcessor::ApplyChangesFromSyncModel(
    const sync_api::BaseTransaction* trans,
    const sync_api::SyncManager::ChangeRecord* changes,
    int change_count) {
  if (!running()) {
    return;
  }
  // TODO(akalin): Normally, we should only have a single change and
  // it should be an update.  However, the syncapi may occasionally
  // generates multiple changes.  When we fix syncapi to not do that,
  // we can remove the extra logic below.  See:
  // http://code.google.com/p/chromium/issues/detail?id=41696 .
  if (change_count < 1) {
    std::string err("Unexpected change_count: ");
    err += change_count;
    error_handler()->OnUnrecoverableError(FROM_HERE, err);
    return;
  }
  if (change_count > 1) {
    LOG(WARNING) << change_count << " theme changes detected; "
                 << "only applying the last one";
  }
  const sync_api::SyncManager::ChangeRecord& change =
      changes[change_count - 1];
  if (change.action != sync_api::SyncManager::ChangeRecord::ACTION_UPDATE) {
    std::string err = "strange theme change.action " + change.action;
    error_handler()->OnUnrecoverableError(FROM_HERE, err);
  }
  sync_pb::ThemeSpecifics theme_specifics;
  // If the action is a delete, simply use the default values for
  // ThemeSpecifics, which would cause the default theme to be set.
  if (change.action != sync_api::SyncManager::ChangeRecord::ACTION_DELETE) {
    sync_api::ReadNode node(trans);
    if (!node.InitByIdLookup(change.id)) {
    error_handler()->OnUnrecoverableError(FROM_HERE,
                                          "Theme node lookup failed.");
      return;
    }
    DCHECK_EQ(node.GetModelType(), syncable::THEMES);
    DCHECK(profile_);
    theme_specifics = node.GetThemeSpecifics();
  }
  StopObserving();
  SetCurrentThemeFromThemeSpecificsIfNecessary(theme_specifics, profile_);
  StartObserving();
}

void ThemeChangeProcessor::StartImpl(Profile* profile) {
  DCHECK(profile);
  profile_ = profile;
  StartObserving();
}

void ThemeChangeProcessor::StopImpl() {
  StopObserving();
  profile_ = NULL;
}

void ThemeChangeProcessor::StartObserving() {
  DCHECK(profile_);
  LOG(INFO) << "Observing BROWSER_THEME_CHANGED, EXTENSION_LOADED, "
            << "and EXTENSION_UNLOADED";
  notification_registrar_.Add(
      this, NotificationType::BROWSER_THEME_CHANGED,
      Source<BrowserThemeProvider>(profile_->GetThemeProvider()));
  notification_registrar_.Add(
      this, NotificationType::EXTENSION_LOADED,
      Source<Profile>(profile_));
  notification_registrar_.Add(
      this, NotificationType::EXTENSION_UNLOADED,
      Source<Profile>(profile_));
}

void ThemeChangeProcessor::StopObserving() {
  DCHECK(profile_);
  LOG(INFO) << "Unobserving all notifications";
  notification_registrar_.RemoveAll();
}

}  // namespace browser_sync
<commit_msg>Current code will definitely crash if ACTION_DELETE is passed to ThemeChangeProcessor, since the error will clear the profile_ without returning, and the profile is accessed later.  Since the code discusses how to process deletes, I think this is the correct fix.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/glue/theme_change_processor.h"

#include "base/logging.h"
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/theme_util.h"
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_source.h"

namespace browser_sync {

namespace {
std::string GetThemeId(Extension* current_theme) {
  if (current_theme) {
    DCHECK(current_theme->is_theme());
  }
  return current_theme ? current_theme->id() : "default/system";
}
}  // namespace

ThemeChangeProcessor::ThemeChangeProcessor(
    UnrecoverableErrorHandler* error_handler)
    : ChangeProcessor(error_handler),
      profile_(NULL) {
  DCHECK(error_handler);
}

ThemeChangeProcessor::~ThemeChangeProcessor() {}

void ThemeChangeProcessor::Observe(NotificationType type,
                                   const NotificationSource& source,
                                   const NotificationDetails& details) {
  DCHECK(running());
  DCHECK(profile_);
  Extension* extension = Details<Extension>(details).ptr();
  std::string current_or_future_theme_id =
      profile_->GetThemeProvider()->GetThemeID();
  Extension* current_theme = profile_->GetTheme();
  switch (type.value) {
    case NotificationType::BROWSER_THEME_CHANGED:
      // We pay attention to this notification only when it signifies
      // that a user changed the theme to the default/system theme, or
      // when it signifies that a user changed the theme to a custom
      // one that was already installed.  Otherwise, current_theme
      // still points to the previous theme until it gets installed
      // and loaded (and we get an EXTENSION_LOADED notification).
      LOG(INFO) << "Got BROWSER_THEME_CHANGED notification for theme "
                << GetThemeId(extension);
      DCHECK_EQ(Source<BrowserThemeProvider>(source).ptr(),
                profile_->GetThemeProvider());
      if (extension != NULL) {
        DCHECK(extension->is_theme());
        DCHECK_EQ(extension->id(), current_or_future_theme_id);
        if (!current_theme || (current_theme->id() != extension->id())) {
          return;
        }
      }
      break;
    case NotificationType::EXTENSION_LOADED:
      // We pay attention to this notification only when it signifies
      // that a theme extension has been loaded because that means
      // that the user set the current theme to a custom theme that
      // needed to be downloaded and installed and that it was
      // installed successfully.
      DCHECK_EQ(Source<Profile>(source).ptr(), profile_);
      CHECK(extension);
      if (!extension->is_theme()) {
        return;
      }
      LOG(INFO) << "Got EXTENSION_LOADED notification for theme "
                << extension->id();
      DCHECK_EQ(extension->id(), current_or_future_theme_id);
      DCHECK_EQ(extension, current_theme);
      break;
    case NotificationType::EXTENSION_UNLOADED:
      // We pay attention to this notification only when it signifies
      // that a theme extension has been unloaded because that means
      // that the user set the current theme to a custom theme and then
      // changed his mind and undid it (reverting to the previous
      // theme).
      DCHECK_EQ(Source<Profile>(source).ptr(), profile_);
      CHECK(extension);
      if (!extension->is_theme()) {
        return;
      }
      LOG(INFO) << "Got EXTENSION_UNLOADED notification for theme "
                << extension->id();
      extension = current_theme;
      break;
    default:
      LOG(DFATAL) << "Unexpected notification received: " << type.value;
      break;
  }

  DCHECK_EQ(extension, current_theme);
  if (extension) {
    DCHECK(extension->is_theme());
  }
  LOG(INFO) << "Theme changed to " << GetThemeId(extension);

  // Here, we know that a theme is being set; the theme is a custom
  // theme iff extension is non-NULL.

  sync_api::WriteTransaction trans(share_handle());
  sync_api::WriteNode node(&trans);
  if (!node.InitByClientTagLookup(syncable::THEMES,
                                  kCurrentThemeClientTag)) {
    std::string err = "Could not create node with client tag: ";
    error_handler()->OnUnrecoverableError(FROM_HERE,
                                          err + kCurrentThemeClientTag);
    return;
  }

  sync_pb::ThemeSpecifics old_theme_specifics = node.GetThemeSpecifics();
  // Make sure to base new_theme_specifics on old_theme_specifics so
  // we preserve the state of use_system_theme_by_default.
  sync_pb::ThemeSpecifics new_theme_specifics = old_theme_specifics;
  GetThemeSpecificsFromCurrentTheme(profile_, &new_theme_specifics);
  // Do a write only if something actually changed so as to guard
  // against cycles.
  if (!AreThemeSpecificsEqual(old_theme_specifics, new_theme_specifics)) {
    node.SetThemeSpecifics(new_theme_specifics);
  }
  return;
}

void ThemeChangeProcessor::ApplyChangesFromSyncModel(
    const sync_api::BaseTransaction* trans,
    const sync_api::SyncManager::ChangeRecord* changes,
    int change_count) {
  if (!running()) {
    return;
  }
  // TODO(akalin): Normally, we should only have a single change and
  // it should be an update.  However, the syncapi may occasionally
  // generates multiple changes.  When we fix syncapi to not do that,
  // we can remove the extra logic below.  See:
  // http://code.google.com/p/chromium/issues/detail?id=41696 .
  if (change_count < 1) {
    std::string err("Unexpected change_count: ");
    err += change_count;
    error_handler()->OnUnrecoverableError(FROM_HERE, err);
    return;
  }
  if (change_count > 1) {
    LOG(WARNING) << change_count << " theme changes detected; "
                 << "only applying the last one";
  }
  const sync_api::SyncManager::ChangeRecord& change =
      changes[change_count - 1];
  if (change.action != sync_api::SyncManager::ChangeRecord::ACTION_UPDATE &&
      change.action != sync_api::SyncManager::ChangeRecord::ACTION_DELETE) {
    std::string err = "strange theme change.action " + change.action;
    error_handler()->OnUnrecoverableError(FROM_HERE, err);
    return;
  }
  sync_pb::ThemeSpecifics theme_specifics;
  // If the action is a delete, simply use the default values for
  // ThemeSpecifics, which would cause the default theme to be set.
  if (change.action != sync_api::SyncManager::ChangeRecord::ACTION_DELETE) {
    sync_api::ReadNode node(trans);
    if (!node.InitByIdLookup(change.id)) {
      error_handler()->OnUnrecoverableError(FROM_HERE,
                                            "Theme node lookup failed.");
      return;
    }
    DCHECK_EQ(node.GetModelType(), syncable::THEMES);
    DCHECK(profile_);
    theme_specifics = node.GetThemeSpecifics();
  }
  StopObserving();
  SetCurrentThemeFromThemeSpecificsIfNecessary(theme_specifics, profile_);
  StartObserving();
}

void ThemeChangeProcessor::StartImpl(Profile* profile) {
  DCHECK(profile);
  profile_ = profile;
  StartObserving();
}

void ThemeChangeProcessor::StopImpl() {
  StopObserving();
  profile_ = NULL;
}

void ThemeChangeProcessor::StartObserving() {
  DCHECK(profile_);
  LOG(INFO) << "Observing BROWSER_THEME_CHANGED, EXTENSION_LOADED, "
            << "and EXTENSION_UNLOADED";
  notification_registrar_.Add(
      this, NotificationType::BROWSER_THEME_CHANGED,
      Source<BrowserThemeProvider>(profile_->GetThemeProvider()));
  notification_registrar_.Add(
      this, NotificationType::EXTENSION_LOADED,
      Source<Profile>(profile_));
  notification_registrar_.Add(
      this, NotificationType::EXTENSION_UNLOADED,
      Source<Profile>(profile_));
}

void ThemeChangeProcessor::StopObserving() {
  DCHECK(profile_);
  LOG(INFO) << "Unobserving all notifications";
  notification_registrar_.RemoveAll();
}

}  // namespace browser_sync
<|endoftext|>


<commit_before>//===- fpcmp.cpp - A fuzzy "cmp" that permits floating point noise --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// fpcmp is a tool that basically works like the 'cmp' tool, except that it can
// tolerate errors due to floating point noise, with the -r option.
//
//===----------------------------------------------------------------------===//

#include "Support/CommandLine.h"
#include "Support/FileUtilities.h"
#include "Config/fcntl.h"
#include "Config/sys/mman.h"
#include <iostream>
#include <cmath>

using namespace llvm;

namespace {
  cl::opt<std::string>
  File1(cl::Positional, cl::desc("<input file #1>"), cl::Required);
  cl::opt<std::string>
  File2(cl::Positional, cl::desc("<input file #2>"), cl::Required);

  cl::opt<double>
  RelTolerance("r", cl::desc("Relative error tolerated"), cl::init(0));
  cl::opt<double>
  AbsTolerance("a", cl::desc("Absolute error tolerated"), cl::init(0));
}

/// OpenFile - mmap the specified file into the address space for reading, and
/// return the length and address of the buffer.
static void OpenFile(const std::string &Filename, unsigned &Len, char* &BufPtr){
  int FD = open(Filename.c_str(), O_RDONLY);
  if (FD == -1 || (Len = getFileSize(Filename)) == ~0U) {
    std::cerr << "Error: cannot open file '" << Filename << "'\n";
    exit(2);
  }

  // mmap in the file all at once...
  BufPtr = (char*)mmap(0, Len, PROT_READ, MAP_PRIVATE, FD, 0);

  if (BufPtr == (char*)MAP_FAILED) {
    std::cerr << "Error: cannot open file '" << Filename << "'\n";
    exit(2);
  }
}

static bool isNumberChar(char C) {
  switch (C) {
  case '0': case '1': case '2': case '3': case '4':
  case '5': case '6': case '7': case '8': case '9':
  case '.': case '+': case '-':
  case 'e':
  case 'E': return true;
  default: return false;
  }
}

static char *BackupNumber(char *Pos, char *FirstChar) {
  while (Pos > FirstChar && isNumberChar(Pos[-1]))
    --Pos;
  return Pos;
}

static void CompareNumbers(char *&F1P, char *&F2P, char *F1End, char *F2End) {
  char *F1NumEnd, *F2NumEnd;
  double V1 = strtod(F1P, &F1NumEnd);
  double V2 = strtod(F2P, &F2NumEnd);

  if (F1NumEnd == F1P || F2NumEnd == F2P) {
    std::cerr << "Comparison failed, not a numeric difference.\n";
    exit(1);
  }

  // Check to see if these are inside the absolute tolerance
  if (AbsTolerance < std::abs(V1-V2)) {
    // Nope, check the relative tolerance...
    double Diff;
    if (V2)
      Diff = std::abs(V1/V2 - 1.0);
    else if (V1)
      Diff = std::abs(V2/V1 - 1.0);
    else
      Diff = 0;  // Both zero.
    if (Diff > RelTolerance) {
      std::cerr << "Compared: " << V1 << " and " << V2 << ": diff = "
                << Diff << "\n";
      std::cerr << "Out of tolerence: rel/abs: " << RelTolerance
                << "/" << AbsTolerance << "\n";
      exit(1);
    }
  }

  // Otherwise, advance our read pointers to the end of the numbers.
  F1P = F1NumEnd;  F2P = F2NumEnd;
}

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv);

  // mmap in the files.
  unsigned File1Len, File2Len;
  char *File1Start, *File2Start;
  OpenFile(File1, File1Len, File1Start);
  OpenFile(File2, File2Len, File2Start);

  // Okay, now that we opened the files, scan them for the first difference.
  char *File1End = File1Start+File1Len;
  char *File2End = File2Start+File2Len;
  char *F1P = File1Start;
  char *F2P = File2Start;

  while (1) {
    // Scan for the end of file or first difference.
    while (F1P < File1End && F2P < File2End && *F1P == *F2P)
      ++F1P, ++F2P;

    if (F1P >= File1End || F2P >= File2End) break;

    // Okay, we must have found a difference.  Backup to the start of the
    // current number each stream is at so that we can compare from the
    // beginning.
    F1P = BackupNumber(F1P, File1Start);
    F2P = BackupNumber(F2P, File2Start);

    // Now that we are at the start of the numbers, compare them, exiting if
    // they don't match.
    CompareNumbers(F1P, F2P, File1End, File2End);
  }

  // Okay, we reached the end of file.  If both files are at the end, we
  // succeeded.
  if (F1P >= File1End && F2P >= File2End) return 0;

  // Otherwise, we might have run off the end due to a number, backup and retry.
  F1P = BackupNumber(F1P, File1Start);
  F2P = BackupNumber(F2P, File2Start);

  // Now that we are at the start of the numbers, compare them, exiting if
  // they don't match.
  CompareNumbers(F1P, F2P, File1End, File2End);

  // If we found the end, we succeeded.
  if (F1P >= File1End && F2P >= File2End) return 0;

  return 1;
}

<commit_msg>Fix typo.<commit_after>//===- fpcmp.cpp - A fuzzy "cmp" that permits floating point noise --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// fpcmp is a tool that basically works like the 'cmp' tool, except that it can
// tolerate errors due to floating point noise, with the -r option.
//
//===----------------------------------------------------------------------===//

#include "Support/CommandLine.h"
#include "Support/FileUtilities.h"
#include "Config/fcntl.h"
#include "Config/sys/mman.h"
#include <iostream>
#include <cmath>

using namespace llvm;

namespace {
  cl::opt<std::string>
  File1(cl::Positional, cl::desc("<input file #1>"), cl::Required);
  cl::opt<std::string>
  File2(cl::Positional, cl::desc("<input file #2>"), cl::Required);

  cl::opt<double>
  RelTolerance("r", cl::desc("Relative error tolerated"), cl::init(0));
  cl::opt<double>
  AbsTolerance("a", cl::desc("Absolute error tolerated"), cl::init(0));
}

/// OpenFile - mmap the specified file into the address space for reading, and
/// return the length and address of the buffer.
static void OpenFile(const std::string &Filename, unsigned &Len, char* &BufPtr){
  int FD = open(Filename.c_str(), O_RDONLY);
  if (FD == -1 || (Len = getFileSize(Filename)) == ~0U) {
    std::cerr << "Error: cannot open file '" << Filename << "'\n";
    exit(2);
  }

  // mmap in the file all at once...
  BufPtr = (char*)mmap(0, Len, PROT_READ, MAP_PRIVATE, FD, 0);

  if (BufPtr == (char*)MAP_FAILED) {
    std::cerr << "Error: cannot open file '" << Filename << "'\n";
    exit(2);
  }
}

static bool isNumberChar(char C) {
  switch (C) {
  case '0': case '1': case '2': case '3': case '4':
  case '5': case '6': case '7': case '8': case '9':
  case '.': case '+': case '-':
  case 'e':
  case 'E': return true;
  default: return false;
  }
}

static char *BackupNumber(char *Pos, char *FirstChar) {
  while (Pos > FirstChar && isNumberChar(Pos[-1]))
    --Pos;
  return Pos;
}

static void CompareNumbers(char *&F1P, char *&F2P, char *F1End, char *F2End) {
  char *F1NumEnd, *F2NumEnd;
  double V1 = strtod(F1P, &F1NumEnd);
  double V2 = strtod(F2P, &F2NumEnd);

  if (F1NumEnd == F1P || F2NumEnd == F2P) {
    std::cerr << "Comparison failed, not a numeric difference.\n";
    exit(1);
  }

  // Check to see if these are inside the absolute tolerance
  if (AbsTolerance < std::abs(V1-V2)) {
    // Nope, check the relative tolerance...
    double Diff;
    if (V2)
      Diff = std::abs(V1/V2 - 1.0);
    else if (V1)
      Diff = std::abs(V2/V1 - 1.0);
    else
      Diff = 0;  // Both zero.
    if (Diff > RelTolerance) {
      std::cerr << "Compared: " << V1 << " and " << V2 << ": diff = "
                << Diff << "\n";
      std::cerr << "Out of tolerance: rel/abs: " << RelTolerance
                << "/" << AbsTolerance << "\n";
      exit(1);
    }
  }

  // Otherwise, advance our read pointers to the end of the numbers.
  F1P = F1NumEnd;  F2P = F2NumEnd;
}

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv);

  // mmap in the files.
  unsigned File1Len, File2Len;
  char *File1Start, *File2Start;
  OpenFile(File1, File1Len, File1Start);
  OpenFile(File2, File2Len, File2Start);

  // Okay, now that we opened the files, scan them for the first difference.
  char *File1End = File1Start+File1Len;
  char *File2End = File2Start+File2Len;
  char *F1P = File1Start;
  char *F2P = File2Start;

  while (1) {
    // Scan for the end of file or first difference.
    while (F1P < File1End && F2P < File2End && *F1P == *F2P)
      ++F1P, ++F2P;

    if (F1P >= File1End || F2P >= File2End) break;

    // Okay, we must have found a difference.  Backup to the start of the
    // current number each stream is at so that we can compare from the
    // beginning.
    F1P = BackupNumber(F1P, File1Start);
    F2P = BackupNumber(F2P, File2Start);

    // Now that we are at the start of the numbers, compare them, exiting if
    // they don't match.
    CompareNumbers(F1P, F2P, File1End, File2End);
  }

  // Okay, we reached the end of file.  If both files are at the end, we
  // succeeded.
  if (F1P >= File1End && F2P >= File2End) return 0;

  // Otherwise, we might have run off the end due to a number, backup and retry.
  F1P = BackupNumber(F1P, File1Start);
  F2P = BackupNumber(F2P, File2Start);

  // Now that we are at the start of the numbers, compare them, exiting if
  // they don't match.
  CompareNumbers(F1P, F2P, File1End, File2End);

  // If we found the end, we succeeded.
  if (F1P >= File1End && F2P >= File2End) return 0;

  return 1;
}

<|endoftext|>