<commit_before>#include "System.h"

Locate Need_Locate;
bool NeedToLoadScript=false;
int8_t NeedToLoadScriptDelay = CHANGELOCATIONDELAY;

int32_t View_start_Loops = 0;

int8_t  SaveSlot = 0;

char *SystemStrings[SYSTEM_STRINGS_NUM];

void SetNeedLocate(uint8_t w, uint8_t r,uint8_t v1, uint8_t v2, int32_t X)
{
    NeedToLoadScript  = true;
    Need_Locate.World = tolower(w);
    Need_Locate.Room  = tolower(r);
    Need_Locate.Node  = tolower(v1);
    Need_Locate.View  = tolower(v2);
    Need_Locate.X     = X;

    if (Need_Locate.World == '0')
    {
        if (GetgVarInt(SLOT_WORLD) == tolower(SystemWorld) &&
                GetgVarInt(SLOT_ROOM) == tolower(SystemRoom))
        {
            Need_Locate.World = GetgVarInt(SLOT_MENU_LASTWORLD);
            Need_Locate.Room  = GetgVarInt(SLOT_MENU_LASTROOM);
            Need_Locate.Node  = GetgVarInt(SLOT_MENU_LASTNODE);
            Need_Locate.View  = GetgVarInt(SLOT_MENU_LASTVIEW);
            Need_Locate.X     = GetgVarInt(SLOT_MENU_LASTVIEW_POS);
        }
        else
        {
            Need_Locate.World = GetgVarInt(SLOT_LASTWORLD);
            Need_Locate.Room  = GetgVarInt(SLOT_LASTROOM);
            Need_Locate.Node  = GetgVarInt(SLOT_LASTNODE);
            Need_Locate.View  = GetgVarInt(SLOT_LASTVIEW);
            Need_Locate.X     = GetgVarInt(SLOT_LASTVIEW_POS);
        }
    }

}

void InitGameLoop()
{
    pzllst *uni = GetUni();
    LoadScriptFile(uni,GetExactFilePath("universe.scr"),false,NULL);

    ScrSys_ChangeLocation(InitWorld,InitRoom,InitNode,InitView,0,true);

    //Hack
    SetDirectgVarInt(SLOT_LASTWORLD, InitWorld);
    SetDirectgVarInt(SLOT_LASTROOM , InitRoom);
    SetDirectgVarInt(SLOT_LASTNODE , InitNode);
    SetDirectgVarInt(SLOT_LASTVIEW , InitView);
    SetDirectgVarInt(SLOT_MENU_LASTWORLD, InitWorld);
    SetDirectgVarInt(SLOT_MENU_LASTROOM , InitRoom);
    SetDirectgVarInt(SLOT_MENU_LASTNODE , InitNode);
    SetDirectgVarInt(SLOT_MENU_LASTVIEW , InitView);
    if (GetgVarInt(SLOT_PANAROTATE_SPEED) == 0)
        SetDirectgVarInt(SLOT_PANAROTATE_SPEED,570);
    if (GetgVarInt(SLOT_KBD_ROTATE_SPEED) == 0)
        SetDirectgVarInt(SLOT_KBD_ROTATE_SPEED,60);
    //\Hack

    // Rend_EF_Wave_Setup(10,360,3,5,4,1,0.1);
}

void EasterEggsAndDebug()
{
    char message_buffer[STRBUFSZ];

    if (KeyAnyHit())
    {

//        if (CheckKeyboardMessage("M?????T?",8))
//        {
//            char abc[6];
//            abc[0] = GetKeyBuffered(6);
//            abc[1] = GetKeyBuffered(5);
//            abc[2] = GetKeyBuffered(4);
//            abc[3] = GetKeyBuffered(3);
//            abc[4] = GetKeyBuffered(2);
//            abc[5] = 0;
//            int ii = atoi(abc);
//            abc[0] = GetKeyBuffered(0);
//            abc[1] = 0;
//            int ii2 = atoi(abc);
//            SetgVarInt(ii,ii2);
//        }

  #ifdef GAME_ZGI
        if (CheckKeyboardMessage("IMNOTDEAF",9))
        {
            //TODO: unknown
        }

        if (CheckKeyboardMessage("3100OPB",7))
        {
            sprintf(message_buffer,"Current location: %c%c%c%c",GetgVarInt(SLOT_WORLD),
                    GetgVarInt(SLOT_ROOM),
                    GetgVarInt(SLOT_NODE),
                    GetgVarInt(SLOT_VIEW));
            game_timed_debug_message(3000,message_buffer);
        }

        if (CheckKeyboardMessage("KILLMENOW",9))
        {
            NeedToLoadScript  = true;
            SetNeedLocate('g', 'j', 'd', 'e', 0);
            SetgVarInt(2201,35);
        }

        if (CheckKeyboardMessage("MIKESPANTS",10) )
        {
            NeedToLoadScript  = true;
            SetNeedLocate('g', 'j', 't', 'm', 0);
        }
 #endif

#ifdef GAME_NEMESIS
        if (CheckKeyboardMessage("CHLOE",5))
        {
            NeedToLoadScript  = true;
            SetNeedLocate('t', 'm', '2', 'g', 0);
            SetgVarInt(224,1);
        }

        if (CheckKeyboardMessage("77MASSAVE",9))
        {
            sprintf(message_buffer,"Current location: %c%c%c%c",GetgVarInt(SLOT_WORLD),
                    GetgVarInt(SLOT_ROOM),
                    GetgVarInt(SLOT_NODE),
                    GetgVarInt(SLOT_VIEW));
            game_timed_debug_message(3000,message_buffer);
        }

        if (CheckKeyboardMessage("IDKFA",5))
        {
            NeedToLoadScript  = true;
            SetNeedLocate('t', 'w', '3', 'f', 0);
            SetgVarInt(249,1);
        }

        if (CheckKeyboardMessage("309NEWDORMA",11) )
        {
            NeedToLoadScript  = true;
            SetNeedLocate('g', 'j', 'g', 'j', 0);
        }

        if (CheckKeyboardMessage("HELLOSAILOR",11) )
        {
            if (GetgVarInt(SLOT_WORLD) == 'v' && GetgVarInt(SLOT_ROOM) == 'b' &&
                GetgVarInt(SLOT_NODE)  == '1' && GetgVarInt(SLOT_VIEW) == '0')
                sprintf(message_buffer,"0 %s 0","v000hpta.raw");
            else
                sprintf(message_buffer,"0 %s 0","v000hnta.raw");

            action_universe_music(message_buffer,0,GetUni());
        }
 #endif

        if (CheckKeyboardMessage("FRAME",5))
        {
            sprintf(message_buffer,"FPS: %d",GetFps());
            game_timed_debug_message(3000,message_buffer);
        }

        if (CheckKeyboardMessage("COMPUTERARCH",12))
        {
            //TODO: var-watcher
        }

        if (CheckKeyboardMessage("XYZZY",5))
            SetDirectgVarInt(SLOT_DEBUGCHEATS, 1 - GetgVarInt(SLOT_DEBUGCHEATS));

        if (GetgVarInt(SLOT_DEBUGCHEATS) == 1)
            if (CheckKeyboardMessage("GO????",6))
            {
                NeedToLoadScript = true;
                SetNeedLocate(GetKeyBuffered(3),
                              GetKeyBuffered(2),
                              GetKeyBuffered(1),
                              GetKeyBuffered(0),0);
            }

        if (KeyDown(SDLK_v) && KeyDown(SDLK_LCTRL))
        {
            sprintf(message_buffer,"<FONT \"ZorkNormal\" BOLD on JUSTIFY center POINT 18 RED 150 GREEN 100 BLUE 50>Zengine %s:<RED 255 GREEN 255 BLUE 255><NEWLINE>%s",ZENGINE_VER,GAME_TITLE);
            game_timed_message(3000,message_buffer);
        }

    }
}

void GameLoop()
{

    Mouse_SetCursor(CURSOR_IDLE);

    if (GetgVarInt(SLOT_MOUSE_RIGHT_CLICK) != 0)
        SetgVarInt(SLOT_MOUSE_RIGHT_CLICK,0);

    if (GetgVarInt(SLOT_MOUSE_DOWN) != 0)
        SetgVarInt(SLOT_MOUSE_DOWN,0);

    if (KeyAnyHit())
        if (GetLastKey() != SDLK_FIRST)
            SetgVarInt(SLOT_KEY_PRESS,GetWinKey(GetLastKey()));

    if (Rend_MouseInGamescr())
    {
        if (MouseUp(SDL_BUTTON_RIGHT))
            SetgVarInt(SLOT_MOUSE_RIGHT_CLICK,1);

#ifdef GAME_NEMESIS
        if (MouseUp(SDL_BUTTON_RIGHT))
            inv_cycle();
#endif
        if (GetgVarInt(SLOT_MOUSE_RIGHT_CLICK) != 1)
            if (MouseDown(SDL_BUTTON_LEFT))
                SetgVarInt(SLOT_MOUSE_DOWN,1);
    }

    ScrSys_ProcessAllRes();

    pzllst *room  = Getroom();
    pzllst *view  = Getview();
    pzllst *world = Getworld();
    pzllst *uni   =  GetUni();

    if (!ScrSys_BreakExec())
        ScrSys_exec_puzzle_list(world);

    if (!ScrSys_BreakExec())
        ScrSys_exec_puzzle_list(room);

    if (!ScrSys_BreakExec())
        ScrSys_exec_puzzle_list(view);

    if (!ScrSys_BreakExec())
        ScrSys_exec_puzzle_list(uni);

    if (!ScrSys_BreakExec())
        menu_UpdateMenuBar();

    MList *ctrl = Getctrl();

    if (!NeedToLoadScript)
    {
        if (!ScrSys_BreakExec())
            Rend_MouseInteractOfRender();

        if (!ScrSys_BreakExec())
            ProcessControls(ctrl);

        if (!ScrSys_BreakExec())
            Rend_RenderFunc();
    }

    if (NeedToLoadScript)
    {
        if (NeedToLoadScriptDelay <= 0)
        {
            NeedToLoadScript=false;
            ScrSys_ChangeLocation(Need_Locate.World,Need_Locate.Room,Need_Locate.Node,Need_Locate.View,Need_Locate.X, false);
            NeedToLoadScriptDelay = CHANGELOCATIONDELAY;
        }
        else
            NeedToLoadScriptDelay--;
    }

    EasterEggsAndDebug();

    Rend_ScreenFlip();
}

void ReadSystemStrings(char *filename)
{
    memset(SystemStrings,0,sizeof(SystemStrings[0])*SYSTEM_STRINGS_NUM);

    mfile *fl = mfopen(filename);

    if (fl == NULL)
    {
        printf("File %s not found\n",filename);
        exit(-1);
    }

    m_wide_to_utf8(fl);

    int32_t ii=0;

    char buf[FILE_LN_BUF];

    while (!mfeof(fl))
    {
        mfgets(buf,FILE_LN_BUF,fl);
        char *str = TrimRight(buf);
        if (ii<SYSTEM_STRINGS_NUM)
        {
            SystemStrings[ii] = (char *)malloc (strlen(str)+1);
            strcpy(SystemStrings[ii],str);
        }
        ii++;
    }

    mfclose(fl);
}

char *GetSystemString(int32_t indx)
{
    if (indx<SYSTEM_STRINGS_NUM)
        return SystemStrings[indx];
    return NULL;
}

void game_timed_message(int32_t milsecs,const char * str)
{
    struct_SubRect *zzz=Rend_CreateSubRect(SUB_DEF_RECT);
    txt_DrawTxtInOneLine(str,zzz->img);
    Rend_DelaySubDelete(zzz,milsecs);
}

void game_timed_debug_message(int32_t milsecs,const char * str)
{
    int32_t tmp_up = 40;
    if (tmp_up < GAMESCREEN_Y)
        tmp_up = GAMESCREEN_Y;
    struct_SubRect *zzz=Rend_CreateSubRect(0,0,GAMESCREEN_W,tmp_up);
    txt_DrawTxtInOneLine(str,zzz->img);
    Rend_DelaySubDelete(zzz,milsecs);
}

void game_delay_message(int32_t milsecs,const char * str)
{
    struct_SubRect *zzz=Rend_CreateSubRect(SUB_DEF_RECT);
    txt_DrawTxtInOneLine(str,zzz->img);
    Rend_RenderFunc();
    Rend_ScreenFlip();

    int32_t cur_time = millisec();
    int32_t nexttime = cur_time + milsecs;

    FlushKeybKey(SDLK_RETURN);
    FlushKeybKey(SDLK_SPACE);
    FlushKeybKey(SDLK_ESCAPE);

    while(!KeyDown(SDLK_SPACE) && !KeyDown(SDLK_RETURN) && !KeyDown(SDLK_ESCAPE) &&  nexttime > cur_time)
    {
        UpdateGameSystem();
        cur_time = millisec();
        Rend_RenderFunc();
        Rend_ScreenFlip();
        SDL_Delay(5);
    }

    Rend_DeleteSubRect(zzz);
}

bool game_question_message(const char * str)
{
    struct_SubRect *zzz=Rend_CreateSubRect(SUB_DEF_RECT);
    txt_DrawTxtInOneLine(str,zzz->img);
    Rend_RenderFunc();
    Rend_ScreenFlip();

    FlushKeybKey(SDLK_y);
    FlushKeybKey(SDLK_n);

    while (!KeyDown(SDLK_y) && !KeyDown(SDLK_n))
    {
        UpdateGameSystem();
        Rend_RenderFunc();
        Rend_ScreenFlip();
        SDL_Delay(5);
    }

    Rend_DeleteSubRect(zzz);

    if (KeyDown(SDLK_y))
        return true;
    return false;
}

void ifquit()
{
    if (game_question_message(GetSystemString(SYSTEM_STR_EXITPROMT)))
        END();
}
<commit_msg>Added shortcuts CTRL+S, CTRL+R, CTRL+Q and CTRL+P<commit_after>#include "System.h"

Locate Need_Locate;
bool NeedToLoadScript=false;
int8_t NeedToLoadScriptDelay = CHANGELOCATIONDELAY;

int32_t View_start_Loops = 0;

int8_t  SaveSlot = 0;

char *SystemStrings[SYSTEM_STRINGS_NUM];

void SetNeedLocate(uint8_t w, uint8_t r,uint8_t v1, uint8_t v2, int32_t X)
{
    NeedToLoadScript  = true;
    Need_Locate.World = tolower(w);
    Need_Locate.Room  = tolower(r);
    Need_Locate.Node  = tolower(v1);
    Need_Locate.View  = tolower(v2);
    Need_Locate.X     = X;

    if (Need_Locate.World == '0')
    {
        if (GetgVarInt(SLOT_WORLD) == tolower(SystemWorld) &&
                GetgVarInt(SLOT_ROOM) == tolower(SystemRoom))
        {
            Need_Locate.World = GetgVarInt(SLOT_MENU_LASTWORLD);
            Need_Locate.Room  = GetgVarInt(SLOT_MENU_LASTROOM);
            Need_Locate.Node  = GetgVarInt(SLOT_MENU_LASTNODE);
            Need_Locate.View  = GetgVarInt(SLOT_MENU_LASTVIEW);
            Need_Locate.X     = GetgVarInt(SLOT_MENU_LASTVIEW_POS);
        }
        else
        {
            Need_Locate.World = GetgVarInt(SLOT_LASTWORLD);
            Need_Locate.Room  = GetgVarInt(SLOT_LASTROOM);
            Need_Locate.Node  = GetgVarInt(SLOT_LASTNODE);
            Need_Locate.View  = GetgVarInt(SLOT_LASTVIEW);
            Need_Locate.X     = GetgVarInt(SLOT_LASTVIEW_POS);
        }
    }

}

void InitGameLoop()
{
    pzllst *uni = GetUni();
    LoadScriptFile(uni,GetExactFilePath("universe.scr"),false,NULL);

    ScrSys_ChangeLocation(InitWorld,InitRoom,InitNode,InitView,0,true);

    //Hack
    SetDirectgVarInt(SLOT_LASTWORLD, InitWorld);
    SetDirectgVarInt(SLOT_LASTROOM , InitRoom);
    SetDirectgVarInt(SLOT_LASTNODE , InitNode);
    SetDirectgVarInt(SLOT_LASTVIEW , InitView);
    SetDirectgVarInt(SLOT_MENU_LASTWORLD, InitWorld);
    SetDirectgVarInt(SLOT_MENU_LASTROOM , InitRoom);
    SetDirectgVarInt(SLOT_MENU_LASTNODE , InitNode);
    SetDirectgVarInt(SLOT_MENU_LASTVIEW , InitView);
    if (GetgVarInt(SLOT_PANAROTATE_SPEED) == 0)
        SetDirectgVarInt(SLOT_PANAROTATE_SPEED,570);
    if (GetgVarInt(SLOT_KBD_ROTATE_SPEED) == 0)
        SetDirectgVarInt(SLOT_KBD_ROTATE_SPEED,60);
    //\Hack

    // Rend_EF_Wave_Setup(10,360,3,5,4,1,0.1);
}

void EasterEggsAndDebug()
{
    char message_buffer[STRBUFSZ];

    if (KeyAnyHit())
    {

//        if (CheckKeyboardMessage("M?????T?",8))
//        {
//            char abc[6];
//            abc[0] = GetKeyBuffered(6);
//            abc[1] = GetKeyBuffered(5);
//            abc[2] = GetKeyBuffered(4);
//            abc[3] = GetKeyBuffered(3);
//            abc[4] = GetKeyBuffered(2);
//            abc[5] = 0;
//            int ii = atoi(abc);
//            abc[0] = GetKeyBuffered(0);
//            abc[1] = 0;
//            int ii2 = atoi(abc);
//            SetgVarInt(ii,ii2);
//        }

  #ifdef GAME_ZGI
        if (CheckKeyboardMessage("IMNOTDEAF",9))
        {
            //TODO: unknown
        }

        if (CheckKeyboardMessage("3100OPB",7))
        {
            sprintf(message_buffer,"Current location: %c%c%c%c",GetgVarInt(SLOT_WORLD),
                    GetgVarInt(SLOT_ROOM),
                    GetgVarInt(SLOT_NODE),
                    GetgVarInt(SLOT_VIEW));
            game_timed_debug_message(3000,message_buffer);
        }

        if (CheckKeyboardMessage("KILLMENOW",9))
        {
            SetNeedLocate('g', 'j', 'd', 'e', 0);
            SetgVarInt(2201,35);
        }

        if (CheckKeyboardMessage("MIKESPANTS",10) )
        {
            NeedToLoadScript  = true;
            SetNeedLocate('g', 'j', 't', 'm', 0);
        }
 #endif

#ifdef GAME_NEMESIS
        if (CheckKeyboardMessage("CHLOE",5))
        {
            SetNeedLocate('t', 'm', '2', 'g', 0);
            SetgVarInt(224,1);
        }

        if (CheckKeyboardMessage("77MASSAVE",9))
        {
            sprintf(message_buffer,"Current location: %c%c%c%c",GetgVarInt(SLOT_WORLD),
                    GetgVarInt(SLOT_ROOM),
                    GetgVarInt(SLOT_NODE),
                    GetgVarInt(SLOT_VIEW));
            game_timed_debug_message(3000,message_buffer);
        }

        if (CheckKeyboardMessage("IDKFA",5))
        {
            SetNeedLocate('t', 'w', '3', 'f', 0);
            SetgVarInt(249,1);
        }

        if (CheckKeyboardMessage("309NEWDORMA",11) )
        {
            SetNeedLocate('g', 'j', 'g', 'j', 0);
        }

        if (CheckKeyboardMessage("HELLOSAILOR",11) )
        {
            if (GetgVarInt(SLOT_WORLD) == 'v' && GetgVarInt(SLOT_ROOM) == 'b' &&
                GetgVarInt(SLOT_NODE)  == '1' && GetgVarInt(SLOT_VIEW) == '0')
                sprintf(message_buffer,"0 %s 0","v000hpta.raw");
            else
                sprintf(message_buffer,"0 %s 0","v000hnta.raw");

            action_universe_music(message_buffer,0,GetUni());
        }
 #endif

        if (CheckKeyboardMessage("FRAME",5))
        {
            sprintf(message_buffer,"FPS: %d",GetFps());
            game_timed_debug_message(3000,message_buffer);
        }

        if (CheckKeyboardMessage("COMPUTERARCH",12))
        {
            //TODO: var-watcher
        }

        if (CheckKeyboardMessage("XYZZY",5))
            SetDirectgVarInt(SLOT_DEBUGCHEATS, 1 - GetgVarInt(SLOT_DEBUGCHEATS));

        if (GetgVarInt(SLOT_DEBUGCHEATS) == 1)
            if (CheckKeyboardMessage("GO????",6))
            {
                SetNeedLocate(GetKeyBuffered(3),
                              GetKeyBuffered(2),
                              GetKeyBuffered(1),
                              GetKeyBuffered(0),0);
            }

        if (KeyDown(SDLK_v) && (KeyDown(SDLK_LCTRL) || KeyDown(SDLK_RCTRL)))
        {
            sprintf(message_buffer,"<FONT \"ZorkNormal\" BOLD on JUSTIFY center POINT 18 RED 150 GREEN 100 BLUE 50>Zengine %s:<RED 255 GREEN 255 BLUE 255><NEWLINE>%s",ZENGINE_VER,GAME_TITLE);
            game_timed_message(3000,message_buffer);
        }

    }
}

void shortcuts()
{
    int32_t m_en = menu_GetMenuBarVal();

    if (KeyHit(SDLK_s) && (KeyDown(SDLK_LCTRL) || KeyDown(SDLK_RCTRL)))
        if (m_en & menu_BAR_SAVE)
            SetNeedLocate(SaveWorld,SaveRoom,SaveNode,SaveView,0);

    if (KeyHit(SDLK_r) && (KeyDown(SDLK_LCTRL) || KeyDown(SDLK_RCTRL)))
        if (m_en & menu_BAR_RESTORE)
            SetNeedLocate(LoadWorld,LoadRoom,LoadNode,LoadView,0);

    if (KeyHit(SDLK_p) && (KeyDown(SDLK_LCTRL) || KeyDown(SDLK_RCTRL)))
        if (m_en & menu_BAR_SETTINGS)
            SetNeedLocate(PrefWorld,PrefRoom,PrefNode,PrefView,0);

    if (KeyHit(SDLK_q) && (KeyDown(SDLK_LCTRL) || KeyDown(SDLK_RCTRL)))
        if (m_en & menu_BAR_EXIT)
            ifquit();
}

void GameLoop()
{

    Mouse_SetCursor(CURSOR_IDLE);

    if (GetgVarInt(SLOT_MOUSE_RIGHT_CLICK) != 0)
        SetgVarInt(SLOT_MOUSE_RIGHT_CLICK,0);

    if (GetgVarInt(SLOT_MOUSE_DOWN) != 0)
        SetgVarInt(SLOT_MOUSE_DOWN,0);

    if (KeyAnyHit())
        if (GetLastKey() != SDLK_FIRST)
            SetgVarInt(SLOT_KEY_PRESS,GetWinKey(GetLastKey()));

    if (Rend_MouseInGamescr())
    {
        if (MouseUp(SDL_BUTTON_RIGHT))
            SetgVarInt(SLOT_MOUSE_RIGHT_CLICK,1);

#ifdef GAME_NEMESIS
        if (MouseUp(SDL_BUTTON_RIGHT))
            inv_cycle();
#endif
        if (GetgVarInt(SLOT_MOUSE_RIGHT_CLICK) != 1)
            if (MouseDown(SDL_BUTTON_LEFT))
                SetgVarInt(SLOT_MOUSE_DOWN,1);
    }

    ScrSys_ProcessAllRes();

    pzllst *room  = Getroom();
    pzllst *view  = Getview();
    pzllst *world = Getworld();
    pzllst *uni   =  GetUni();

    if (!ScrSys_BreakExec())
        ScrSys_exec_puzzle_list(world);

    if (!ScrSys_BreakExec())
        ScrSys_exec_puzzle_list(room);

    if (!ScrSys_BreakExec())
        ScrSys_exec_puzzle_list(view);

    if (!ScrSys_BreakExec())
        ScrSys_exec_puzzle_list(uni);

    if (!ScrSys_BreakExec())
        menu_UpdateMenuBar();

    MList *ctrl = Getctrl();

    if (!NeedToLoadScript)
    {
        if (!ScrSys_BreakExec())
            Rend_MouseInteractOfRender();

        if (!ScrSys_BreakExec())
            ProcessControls(ctrl);

        if (!ScrSys_BreakExec())
            Rend_RenderFunc();
    }

    if (NeedToLoadScript)
    {
        if (NeedToLoadScriptDelay <= 0)
        {
            NeedToLoadScript=false;
            ScrSys_ChangeLocation(Need_Locate.World,Need_Locate.Room,Need_Locate.Node,Need_Locate.View,Need_Locate.X, false);
            NeedToLoadScriptDelay = CHANGELOCATIONDELAY;
        }
        else
            NeedToLoadScriptDelay--;
    }

    EasterEggsAndDebug();
    shortcuts();

    Rend_ScreenFlip();
}

void ReadSystemStrings(char *filename)
{
    memset(SystemStrings,0,sizeof(SystemStrings[0])*SYSTEM_STRINGS_NUM);

    mfile *fl = mfopen(filename);

    if (fl == NULL)
    {
        printf("File %s not found\n",filename);
        exit(-1);
    }

    m_wide_to_utf8(fl);

    int32_t ii=0;

    char buf[FILE_LN_BUF];

    while (!mfeof(fl))
    {
        mfgets(buf,FILE_LN_BUF,fl);
        char *str = TrimRight(buf);
        if (ii<SYSTEM_STRINGS_NUM)
        {
            SystemStrings[ii] = (char *)malloc (strlen(str)+1);
            strcpy(SystemStrings[ii],str);
        }
        ii++;
    }

    mfclose(fl);
}

char *GetSystemString(int32_t indx)
{
    if (indx<SYSTEM_STRINGS_NUM)
        return SystemStrings[indx];
    return NULL;
}

void game_timed_message(int32_t milsecs,const char * str)
{
    struct_SubRect *zzz=Rend_CreateSubRect(SUB_DEF_RECT);
    txt_DrawTxtInOneLine(str,zzz->img);
    Rend_DelaySubDelete(zzz,milsecs);
}

void game_timed_debug_message(int32_t milsecs,const char * str)
{
    int32_t tmp_up = 40;
    if (tmp_up < GAMESCREEN_Y)
        tmp_up = GAMESCREEN_Y;
    struct_SubRect *zzz=Rend_CreateSubRect(0,0,GAMESCREEN_W,tmp_up);
    txt_DrawTxtInOneLine(str,zzz->img);
    Rend_DelaySubDelete(zzz,milsecs);
}

void game_delay_message(int32_t milsecs,const char * str)
{
    struct_SubRect *zzz=Rend_CreateSubRect(SUB_DEF_RECT);
    txt_DrawTxtInOneLine(str,zzz->img);
    Rend_RenderFunc();
    Rend_ScreenFlip();

    int32_t cur_time = millisec();
    int32_t nexttime = cur_time + milsecs;

    FlushKeybKey(SDLK_RETURN);
    FlushKeybKey(SDLK_SPACE);
    FlushKeybKey(SDLK_ESCAPE);

    while(!KeyDown(SDLK_SPACE) && !KeyDown(SDLK_RETURN) && !KeyDown(SDLK_ESCAPE) &&  nexttime > cur_time)
    {
        UpdateGameSystem();
        cur_time = millisec();
        Rend_RenderFunc();
        Rend_ScreenFlip();
        SDL_Delay(5);
    }

    Rend_DeleteSubRect(zzz);
}

bool game_question_message(const char * str)
{
    struct_SubRect *zzz=Rend_CreateSubRect(SUB_DEF_RECT);
    txt_DrawTxtInOneLine(str,zzz->img);
    Rend_RenderFunc();
    Rend_ScreenFlip();

    FlushKeybKey(SDLK_y);
    FlushKeybKey(SDLK_n);

    while (!KeyDown(SDLK_y) && !KeyDown(SDLK_n))
    {
        UpdateGameSystem();
        Rend_RenderFunc();
        Rend_ScreenFlip();
        SDL_Delay(5);
    }

    Rend_DeleteSubRect(zzz);

    if (KeyDown(SDLK_y))
        return true;
    return false;
}

void ifquit()
{
    if (game_question_message(GetSystemString(SYSTEM_STR_EXITPROMT)))
        END();
}
<|endoftext|>


<commit_before>#include "main.hpp"

const bool is_name[256]={false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
	is_true_name[256]={false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true,true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false};

int main(int argc, char** argv)
{
	ios_base::sync_with_stdio(false);
	if(argc<2)
	{
		cerr << "Usage:\ncr <file name>" << endl;
		return 1;
	}
	string file_name=argv[1];
	// cin >> file_name;
	fstream file(file_name.c_str(), ios::in);
	if(file.good())
	{
		coloring::init();
		// fstream out((file_name+".html").c_str(), ios::out);
		cout << "
\n
\n
\n\n
\n1\n";
		string input, tmp;
		getline(file, input);
		unsigned line=1;
		while(file.good())
		{
			cout << ++line << '\n';
			input+='\n';
			getline(file, tmp);
			input+=tmp;
		}
		cout << "
\n	\n\n
\n";
		coloring::color_code(input, cout);
		cout << "

";
	}
	else cout << "Cannot open file" << endl;
return 0;
}<commit_msg>Little 'const'<commit_after>#include "main.hpp"

const bool is_name[256]={false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
	is_true_name[256]={false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true,true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false};

int main(int argc, char const **argv)
{
	ios_base::sync_with_stdio(false);
	if(argc<2)
	{
		cerr << "Usage:\ncr <file name>" << endl;
		return 1;
	}
	string file_name=argv[1];
	// cin >> file_name;
	fstream file(file_name.c_str(), ios::in);
	if(file.good())
	{
		coloring::init();
		// fstream out((file_name+".html").c_str(), ios::out);
		cout << "
\n
\n
\n\n
\n1\n";
		string input, tmp;
		getline(file, input);
		unsigned line=1;
		while(file.good())
		{
			cout << ++line << '\n';
			input+='\n';
			getline(file, tmp);
			input+=tmp;
		}
		cout << "
\n	\n\n
\n";
		coloring::color_code(input, cout);
		cout << "

";
	}
	else cout << "Cannot open file" << endl;
return 0;
}<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/bind.hpp>

#include <libtorrent/io.hpp>
#include <libtorrent/invariant_check.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/logging.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/hasher.hpp>

#include <fstream>

using boost::posix_time::ptime;
using boost::posix_time::time_duration;
using boost::posix_time::microsec_clock;
using boost::posix_time::seconds;
using boost::posix_time::milliseconds;
using boost::shared_ptr;
using boost::bind;

namespace libtorrent { namespace dht
{

namespace io = libtorrent::detail;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(rpc)
#endif

node_id generate_id();

rpc_manager::rpc_manager(fun const& f, node_id const& our_id
	, routing_table& table, send_fun const& sf)
	: m_next_transaction_id(rand() % max_transactions)
	, m_oldest_transaction_id(m_next_transaction_id)
	, m_incoming(f)
	, m_send(sf)
	, m_our_id(our_id)
	, m_table(table)
	, m_timer(boost::posix_time::microsec_clock::universal_time())
	, m_random_number(generate_id())
	, m_destructing(false)
{
	std::srand(time(0));
}

rpc_manager::~rpc_manager()
{
	m_destructing = true;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(rpc) << "Destructing";
#endif
	std::for_each(m_aborted_transactions.begin(), m_aborted_transactions.end()
		, bind(&observer::abort, _1));

	for (transactions_t::iterator i = m_transactions.begin()
		, end(m_transactions.end()); i != end; ++i)
	{
		if (*i) (*i)->abort();
	}
}

#ifndef NDEBUG
void rpc_manager::check_invariant() const
{
	assert(m_oldest_transaction_id >= 0);
	assert(m_oldest_transaction_id < max_transactions);
	assert(m_next_transaction_id >= 0);
	assert(m_next_transaction_id < max_transactions);
	assert(!m_transactions[m_next_transaction_id]);

	for (int i = (m_next_transaction_id + 1) % max_transactions;
		i != m_oldest_transaction_id; i = (i + 1) % max_transactions)
	{
		assert(!m_transactions[i]);
	}
}
#endif

bool rpc_manager::incoming(msg const& m)
{
	INVARIANT_CHECK;

	if (m_destructing) return false;

	if (m.reply)
	{
		// if we don't have the transaction id in our
		// request list, ignore the packet

		if (m.transaction_id.size() != 2)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with invalid transaction id size: "
				<< m.transaction_id.size() << " from " << m.addr;
#endif
			return false;
		}

		std::string::const_iterator i = m.transaction_id.begin();
		int tid = io::read_uint16(i);

		if (tid >= (int)m_transactions.size()
			|| tid < 0)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with unknown transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

		boost::shared_ptr<observer> o = m_transactions[tid];

		if (!o)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with unknown transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

		if (m.addr != o->target_addr)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with incorrect address and valid transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		std::ofstream reply_stats("libtorrent_logs/round_trip_ms.log", std::ios::app);
		reply_stats << m.addr << "\t" << (microsec_clock::universal_time()
			- o->sent).total_milliseconds() << std::endl;
#endif
		o->reply(m);
		m_transactions[tid].reset();

		if (m.piggy_backed_ping)
		{
			// there is a ping request piggy
			// backed in this reply
			msg ph;
			ph.message_id = messages::ping;
			ph.transaction_id = m.ping_transaction_id;
			ph.id = m_our_id;
			ph.addr = m.addr;

			msg empty;

			reply(empty, ph);
		}
		return m_table.node_seen(m.id, m.addr);
	}
	else
	{
		// this is an incoming request
		m_incoming(m);
	}
	return false;
}

time_duration rpc_manager::tick()
{
	INVARIANT_CHECK;

	using boost::posix_time::microsec_clock;

	const int timeout_ms = 20 * 1000;

	//	look for observers that has timed out

	if (m_next_transaction_id == m_oldest_transaction_id) return milliseconds(timeout_ms);

	std::vector<shared_ptr<observer> > timeouts;

	for (;m_next_transaction_id != m_oldest_transaction_id;
		m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions)
	{
		assert(m_oldest_transaction_id >= 0);
		assert(m_oldest_transaction_id < max_transactions);

		boost::shared_ptr<observer> o = m_transactions[m_oldest_transaction_id];
		if (!o) continue;

		time_duration diff = o->sent + milliseconds(timeout_ms)
			- microsec_clock::universal_time();
		if (diff > seconds(0))
		{
			if (diff < seconds(1)) return seconds(1);
			return diff;
		}

		try
		{
			m_transactions[m_oldest_transaction_id].reset();
			timeouts.push_back(o);
		} catch (std::exception) {}
	}

	check_invariant();

	std::for_each(timeouts.begin(), timeouts.end(), bind(&observer::timeout, _1));
	timeouts.clear();

	// clear the aborted transactions, will likely
	// generate new requests. We need to swap, since the
	// destrutors may add more observers to the m_aborted_transactions
	std::vector<shared_ptr<observer> >().swap(m_aborted_transactions);
	return milliseconds(timeout_ms);
}

unsigned int rpc_manager::new_transaction_id(shared_ptr<observer> o)
{
	INVARIANT_CHECK;

	unsigned int tid = m_next_transaction_id;
	m_next_transaction_id = (m_next_transaction_id + 1) % max_transactions;
	if (m_transactions[m_next_transaction_id])
	{
		// moving the observer into the set of aborted transactions
		// it will prevent it from spawning new requests right now,
		// since that would break the invariant
		m_aborted_transactions.push_back(m_transactions[m_next_transaction_id]);
		m_transactions[m_next_transaction_id].reset();
		assert(m_oldest_transaction_id == m_next_transaction_id);
	}
	assert(!m_transactions[tid]);
	m_transactions[tid] = o;
	if (m_oldest_transaction_id == m_next_transaction_id)
	{
		m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(rpc) << "WARNING: transaction limit reached! Too many concurrent"
			" messages! limit: " << (int)max_transactions;
#endif
		update_oldest_transaction_id();
	}

	return tid;
}

void rpc_manager::update_oldest_transaction_id()
{
	INVARIANT_CHECK;

	assert(m_oldest_transaction_id != m_next_transaction_id);
	while (!m_transactions[m_oldest_transaction_id])
	{
		m_oldest_transaction_id = (m_oldest_transaction_id + 1)
			% max_transactions;
		if (m_oldest_transaction_id == m_next_transaction_id)
			break;
	}
}

void rpc_manager::invoke(int message_id, udp::endpoint target_addr
	, shared_ptr<observer> o)
{
	INVARIANT_CHECK;

	if (m_destructing)
	{
		o->abort();
		return;
	}

	msg m;
	m.message_id = message_id;
	m.reply = false;
	m.id = m_our_id;
	m.addr = target_addr;
	assert(!m_transactions[m_next_transaction_id]);
	try
	{
		m.transaction_id.clear();
		std::back_insert_iterator<std::string> out(m.transaction_id);
		io::write_uint16(m_next_transaction_id, out);

		o->send(m);

		o->sent = boost::posix_time::microsec_clock::universal_time();
		o->target_addr = target_addr;

	#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(rpc) << "Invoking " << messages::ids[message_id]
			<< " -> " << target_addr;
	#endif
		m_send(m);
		new_transaction_id(o);
	}
	catch (std::exception&)
	{
		assert(false);
	}
}

void rpc_manager::reply(msg& m, msg const& reply_to)
{
	INVARIANT_CHECK;

	if (m_destructing) return;

	if (m.message_id != messages::error)
		m.message_id = reply_to.message_id;
	m.addr = reply_to.addr;
	m.reply = true;
	m.piggy_backed_ping = false;
	m.id = m_our_id;
	m.transaction_id = reply_to.transaction_id;

	m_send(m);
}

namespace
{
	struct dummy_observer : observer
	{
		virtual void reply(msg const&) {}
		virtual void timeout() {}
		virtual void send(msg&) {}
		void abort() {}
	};
}

void rpc_manager::reply_with_ping(msg& m, msg const& reply_to)
{
	INVARIANT_CHECK;

	if (m_destructing) return;

	if (m.message_id != messages::error)
		m.message_id = reply_to.message_id;
	m.addr = reply_to.addr;
	m.reply = true;
	m.piggy_backed_ping = true;
	m.id = m_our_id;
	m.transaction_id = reply_to.transaction_id;

	try
	{
		m.ping_transaction_id.clear();
		std::back_insert_iterator<std::string> out(m.ping_transaction_id);
		io::write_uint16(m_next_transaction_id, out);

		boost::shared_ptr<observer> o(new dummy_observer);
		assert(!m_transactions[m_next_transaction_id]);
		o->sent = boost::posix_time::microsec_clock::universal_time();
		o->target_addr = m.addr;

		m_send(m);
		new_transaction_id(o);
	}
	catch (std::exception& e)
	{
		assert(false);
	}
}

} } // namespace libtorrent::dht

<commit_msg>removed invariant_check() left in by mistake<commit_after>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/bind.hpp>

#include <libtorrent/io.hpp>
#include <libtorrent/invariant_check.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/logging.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/hasher.hpp>

#include <fstream>

using boost::posix_time::ptime;
using boost::posix_time::time_duration;
using boost::posix_time::microsec_clock;
using boost::posix_time::seconds;
using boost::posix_time::milliseconds;
using boost::shared_ptr;
using boost::bind;

namespace libtorrent { namespace dht
{

namespace io = libtorrent::detail;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(rpc)
#endif

node_id generate_id();

rpc_manager::rpc_manager(fun const& f, node_id const& our_id
	, routing_table& table, send_fun const& sf)
	: m_next_transaction_id(rand() % max_transactions)
	, m_oldest_transaction_id(m_next_transaction_id)
	, m_incoming(f)
	, m_send(sf)
	, m_our_id(our_id)
	, m_table(table)
	, m_timer(boost::posix_time::microsec_clock::universal_time())
	, m_random_number(generate_id())
	, m_destructing(false)
{
	std::srand(time(0));
}

rpc_manager::~rpc_manager()
{
	m_destructing = true;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(rpc) << "Destructing";
#endif
	std::for_each(m_aborted_transactions.begin(), m_aborted_transactions.end()
		, bind(&observer::abort, _1));

	for (transactions_t::iterator i = m_transactions.begin()
		, end(m_transactions.end()); i != end; ++i)
	{
		if (*i) (*i)->abort();
	}
}

#ifndef NDEBUG
void rpc_manager::check_invariant() const
{
	assert(m_oldest_transaction_id >= 0);
	assert(m_oldest_transaction_id < max_transactions);
	assert(m_next_transaction_id >= 0);
	assert(m_next_transaction_id < max_transactions);
	assert(!m_transactions[m_next_transaction_id]);

	for (int i = (m_next_transaction_id + 1) % max_transactions;
		i != m_oldest_transaction_id; i = (i + 1) % max_transactions)
	{
		assert(!m_transactions[i]);
	}
}
#endif

bool rpc_manager::incoming(msg const& m)
{
	INVARIANT_CHECK;

	if (m_destructing) return false;

	if (m.reply)
	{
		// if we don't have the transaction id in our
		// request list, ignore the packet

		if (m.transaction_id.size() != 2)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with invalid transaction id size: "
				<< m.transaction_id.size() << " from " << m.addr;
#endif
			return false;
		}

		std::string::const_iterator i = m.transaction_id.begin();
		int tid = io::read_uint16(i);

		if (tid >= (int)m_transactions.size()
			|| tid < 0)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with unknown transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

		boost::shared_ptr<observer> o = m_transactions[tid];

		if (!o)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with unknown transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

		if (m.addr != o->target_addr)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with incorrect address and valid transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		std::ofstream reply_stats("libtorrent_logs/round_trip_ms.log", std::ios::app);
		reply_stats << m.addr << "\t" << (microsec_clock::universal_time()
			- o->sent).total_milliseconds() << std::endl;
#endif
		o->reply(m);
		m_transactions[tid].reset();

		if (m.piggy_backed_ping)
		{
			// there is a ping request piggy
			// backed in this reply
			msg ph;
			ph.message_id = messages::ping;
			ph.transaction_id = m.ping_transaction_id;
			ph.id = m_our_id;
			ph.addr = m.addr;

			msg empty;

			reply(empty, ph);
		}
		return m_table.node_seen(m.id, m.addr);
	}
	else
	{
		// this is an incoming request
		m_incoming(m);
	}
	return false;
}

time_duration rpc_manager::tick()
{
	INVARIANT_CHECK;

	using boost::posix_time::microsec_clock;

	const int timeout_ms = 20 * 1000;

	//	look for observers that has timed out

	if (m_next_transaction_id == m_oldest_transaction_id) return milliseconds(timeout_ms);

	std::vector<shared_ptr<observer> > timeouts;

	for (;m_next_transaction_id != m_oldest_transaction_id;
		m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions)
	{
		assert(m_oldest_transaction_id >= 0);
		assert(m_oldest_transaction_id < max_transactions);

		boost::shared_ptr<observer> o = m_transactions[m_oldest_transaction_id];
		if (!o) continue;

		time_duration diff = o->sent + milliseconds(timeout_ms)
			- microsec_clock::universal_time();
		if (diff > seconds(0))
		{
			if (diff < seconds(1)) return seconds(1);
			return diff;
		}

		try
		{
			m_transactions[m_oldest_transaction_id].reset();
			timeouts.push_back(o);
		} catch (std::exception) {}
	}

	std::for_each(timeouts.begin(), timeouts.end(), bind(&observer::timeout, _1));
	timeouts.clear();

	// clear the aborted transactions, will likely
	// generate new requests. We need to swap, since the
	// destrutors may add more observers to the m_aborted_transactions
	std::vector<shared_ptr<observer> >().swap(m_aborted_transactions);
	return milliseconds(timeout_ms);
}

unsigned int rpc_manager::new_transaction_id(shared_ptr<observer> o)
{
	INVARIANT_CHECK;

	unsigned int tid = m_next_transaction_id;
	m_next_transaction_id = (m_next_transaction_id + 1) % max_transactions;
	if (m_transactions[m_next_transaction_id])
	{
		// moving the observer into the set of aborted transactions
		// it will prevent it from spawning new requests right now,
		// since that would break the invariant
		m_aborted_transactions.push_back(m_transactions[m_next_transaction_id]);
		m_transactions[m_next_transaction_id].reset();
		assert(m_oldest_transaction_id == m_next_transaction_id);
	}
	assert(!m_transactions[tid]);
	m_transactions[tid] = o;
	if (m_oldest_transaction_id == m_next_transaction_id)
	{
		m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(rpc) << "WARNING: transaction limit reached! Too many concurrent"
			" messages! limit: " << (int)max_transactions;
#endif
		update_oldest_transaction_id();
	}

	return tid;
}

void rpc_manager::update_oldest_transaction_id()
{
	INVARIANT_CHECK;

	assert(m_oldest_transaction_id != m_next_transaction_id);
	while (!m_transactions[m_oldest_transaction_id])
	{
		m_oldest_transaction_id = (m_oldest_transaction_id + 1)
			% max_transactions;
		if (m_oldest_transaction_id == m_next_transaction_id)
			break;
	}
}

void rpc_manager::invoke(int message_id, udp::endpoint target_addr
	, shared_ptr<observer> o)
{
	INVARIANT_CHECK;

	if (m_destructing)
	{
		o->abort();
		return;
	}

	msg m;
	m.message_id = message_id;
	m.reply = false;
	m.id = m_our_id;
	m.addr = target_addr;
	assert(!m_transactions[m_next_transaction_id]);
	try
	{
		m.transaction_id.clear();
		std::back_insert_iterator<std::string> out(m.transaction_id);
		io::write_uint16(m_next_transaction_id, out);

		o->send(m);

		o->sent = boost::posix_time::microsec_clock::universal_time();
		o->target_addr = target_addr;

	#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(rpc) << "Invoking " << messages::ids[message_id]
			<< " -> " << target_addr;
	#endif
		m_send(m);
		new_transaction_id(o);
	}
	catch (std::exception&)
	{
		assert(false);
	}
}

void rpc_manager::reply(msg& m, msg const& reply_to)
{
	INVARIANT_CHECK;

	if (m_destructing) return;

	if (m.message_id != messages::error)
		m.message_id = reply_to.message_id;
	m.addr = reply_to.addr;
	m.reply = true;
	m.piggy_backed_ping = false;
	m.id = m_our_id;
	m.transaction_id = reply_to.transaction_id;

	m_send(m);
}

namespace
{
	struct dummy_observer : observer
	{
		virtual void reply(msg const&) {}
		virtual void timeout() {}
		virtual void send(msg&) {}
		void abort() {}
	};
}

void rpc_manager::reply_with_ping(msg& m, msg const& reply_to)
{
	INVARIANT_CHECK;

	if (m_destructing) return;

	if (m.message_id != messages::error)
		m.message_id = reply_to.message_id;
	m.addr = reply_to.addr;
	m.reply = true;
	m.piggy_backed_ping = true;
	m.id = m_our_id;
	m.transaction_id = reply_to.transaction_id;

	try
	{
		m.ping_transaction_id.clear();
		std::back_insert_iterator<std::string> out(m.ping_transaction_id);
		io::write_uint16(m_next_transaction_id, out);

		boost::shared_ptr<observer> o(new dummy_observer);
		assert(!m_transactions[m_next_transaction_id]);
		o->sent = boost::posix_time::microsec_clock::universal_time();
		o->target_addr = m.addr;

		m_send(m);
		new_transaction_id(o);
	}
	catch (std::exception& e)
	{
		assert(false);
	}
}

} } // namespace libtorrent::dht

<|endoftext|>


<commit_before>#include "dlib/bam_util.h"
#include <getopt.h>
#include <functional>

int usage(char **argv, int retcode=EXIT_FAILURE) {
    fprintf(stderr, "bmftools %s <-l output_compression_level> in.bam out.bam\n"
                    "Use - for stdin or stdout.\n", argv[0]);
    return retcode;
}

struct opts {
    uint32_t minFM:14;
    uint32_t v:1;
    uint32_t skip_flag:16;
    uint32_t require_flag:16;
    uint32_t minMQ:8;
};

#define TEST(b, options) \
        (bam_itag(b, "FM") < (int)((opts *)options)->minFM ||\
                   b->core.qual < ((opts *)options)->minMQ ||\
                   (b->core.flag & ((opts *)options)->skip_flag) ||\
                   ((b->core.flag & ((opts *)options)->require_flag) == 0))
int bam_test(bam1_t *b, void *options) {
    return ((opts *)options)->v ? !TEST(b, options): TEST(b, options);
}

#undef TEST

int filter_main(int argc, char *argv[]) {
    if(argc < 3) {
        return usage(argv);
    }
    if(strcmp(argv[1], "--help") == 0) {
        return usage(argv, EXIT_SUCCESS);
    }
    int c;
    char out_mode[4] = "wb";
    opts param = {0};
    while((c = getopt(argc, argv, "m:F:f:l:hv?")) > -1) {
        switch(c) {
        case 'm': param.minMQ = strtoul(optarg, NULL, 0); break;
        case 'F': param.skip_flag = strtoul(optarg, NULL, 0); break;
        case 'f': param.require_flag = strtoul(optarg, NULL, 0); break;
        case 'v': param.v = 1; break;
        case 'l': out_mode[2] = atoi(optarg) % 10 + '0'; break;
        case 'h': case '?': return usage(argv, EXIT_SUCCESS);
        }
    }
    if(argc - 2 != optind) {
        LOG_EXIT("Required: precisely two positional arguments (in bam, out bam).\n");
    }
    // Actually this function. You can't really apply a null function....
    // Actually create your type for data and then provide it if needed.
    dlib::bam_apply_function(argv[optind], argv[optind + 1], bam_test, (void *)&param, out_mode);
    return EXIT_SUCCESS;
}

<commit_msg>Added bed region test to bmftools filter.<commit_after>#include "dlib/bam_util.h"
#include "dlib/bed_util.h"
#include <getopt.h>
#include <functional>

int usage(char **argv, int retcode=EXIT_FAILURE) {
    fprintf(stderr, "bmftools %s <-l output_compression_level> in.bam out.bam\n"
                    "Use - for stdin or stdout.\n", argv[0]);
    return retcode;
}

struct opts {
    uint32_t minFM:14;
    uint32_t v:1;
    uint32_t skip_flag:16;
    uint32_t require_flag:16;
    uint32_t minMQ:8;
    khash_t(bed) *bed;
};

#define TEST(b, options) \
        (\
             bam_itag(b, "FM") < (int)((opts *)options)->minFM ||\
             b->core.qual < ((opts *)options)->minMQ ||\
             (b->core.flag & ((opts *)options)->skip_flag) ||\
             ((b->core.flag & ((opts *)options)->require_flag) == 0) ||\
             !bed_test(b, ((opts *)options)->bed)\
        )

int bam_test(bam1_t *b, void *options) {
    return ((opts *)options)->v ? !TEST(b, options): TEST(b, options);
}

#undef TEST

int filter_main(int argc, char *argv[]) {
    if(argc < 3) {
        return usage(argv);
    }
    if(strcmp(argv[1], "--help") == 0) {
        return usage(argv, EXIT_SUCCESS);
    }
    int c;
    char out_mode[4] = "wb";
    opts param = {0};
    char *bedpath = NULL;
    while((c = getopt(argc, argv, "b:m:F:f:l:hv?")) > -1) {
        switch(c) {
        case 'b': bedpath = optarg; break;
        case 'm': param.minMQ = strtoul(optarg, NULL, 0); break;
        case 'F': param.skip_flag = strtoul(optarg, NULL, 0); break;
        case 'f': param.require_flag = strtoul(optarg, NULL, 0); break;
        case 'v': param.v = 1; break;
        case 'l': out_mode[2] = atoi(optarg) % 10 + '0'; break;
        case 'h': case '?': return usage(argv, EXIT_SUCCESS);
        }
    }
    if(argc - 2 != optind) {
        LOG_EXIT("Required: precisely two positional arguments (in bam, out bam).\n");
    }
    if(bedpath) {
        // This doesn't properly handle streaming....
        samFile *fp = sam_open(argv[optind], "r");
        bam_hdr_t *hdr = sam_hdr_read(fp);
        sam_close(fp);
        param.bed = parse_bed_hash(bedpath, hdr, 0);
        bam_hdr_destroy(hdr);
    }
    // Actually this function. You can't really apply a null function....
    // Actually create your type for data and then provide it if needed.
    dlib::bam_apply_function(argv[optind], argv[optind + 1], bam_test, (void *)&param, out_mode);
    if(param.bed) bed_destroy_hash((void *)param.bed);
    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "bp_control.hxx"
#include "bp_stats.hxx"
#include "control_distribute.hxx"
#include "control_server.hxx"
#include "control_local.hxx"
#include "bp_instance.hxx"
#include "translation/Request.hxx"
#include "translation/Cache.hxx"
#include "translation/Protocol.hxx"
#include "translation/InvalidateParser.hxx"
#include "tpool.hxx"
#include "pool.hxx"
#include "net/UdpDistribute.hxx"
#include "net/SocketAddress.hxx"
#include "net/IPv4Address.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Exception.hxx"
#include "util/Macros.hxx"

#include <daemon/log.h>

#include <assert.h>
#include <string.h>

static void
control_tcache_invalidate(BpInstance *instance,
                          const void *payload, size_t payload_length)
{
    if (payload_length == 0) {
        /* flush the translation cache if the payload is empty */
        translate_cache_flush(*instance->translate_cache);
        return;
    }

    const AutoRewindPool auto_rewind(*tpool);

    TranslationInvalidateRequest request;

    try {
        request = ParseTranslationInvalidateRequest(*tpool,
                                                    payload, payload_length);
    } catch (...) {
        daemon_log(2, "malformed TCACHE_INVALIDATE control packet: %s\n",
                   GetFullMessage(std::current_exception()).c_str());
        return;
    }

    translate_cache_invalidate(*instance->translate_cache, request,
                               ConstBuffer<TranslationCommand>(request.commands.raw(),
                                                               request.commands.size()),
                               request.site);
}

static void
query_stats(BpInstance *instance, ControlServer *server,
            SocketAddress address)
{
    if (address.GetSize() == 0)
        /* TODO: this packet was forwarded by the master process, and
           has no source address; however, the master process must get
           statistics from all worker processes (even those that have
           exited already) */
        return;

    struct beng_control_stats stats;
    bp_get_stats(instance, &stats);

    try {
        server->Reply(address,
                      CONTROL_STATS, &stats, sizeof(stats));
    } catch (const std::runtime_error &e) {
        daemon_log(3, "%s\n", e.what());
    }
}

static void
handle_control_packet(BpInstance *instance, ControlServer *server,
                      enum beng_control_command command,
                      const void *payload, size_t payload_length,
                      SocketAddress address)
{
    daemon_log(5, "control command=%d payload_length=%zu\n",
               command, payload_length);

    /* only local clients are allowed to use most commands */
    const bool is_privileged = address.GetFamily() == AF_LOCAL;

    switch (command) {
    case CONTROL_NOP:
        /* duh! */
        break;

    case CONTROL_TCACHE_INVALIDATE:
        control_tcache_invalidate(instance, payload, payload_length);
        break;

    case CONTROL_DUMP_POOLS:
        if (is_privileged)
            pool_dump_tree(instance->root_pool);
        break;

    case CONTROL_ENABLE_NODE:
    case CONTROL_FADE_NODE:
    case CONTROL_NODE_STATUS:
        /* only for beng-lb */
        break;

    case CONTROL_STATS:
        query_stats(instance, server, address);
        break;

    case CONTROL_VERBOSE:
        if (is_privileged && payload_length == 1)
            daemon_log_config.verbose = *(const uint8_t *)payload;
        break;

    case CONTROL_FADE_CHILDREN:
        if (payload_length > 0)
            /* tagged fade is allowed for any unprivileged client */
            instance->FadeTaggedChildren(std::string((const char *)payload,
                                                     payload_length).c_str());
        else if (is_privileged)
            /* unconditional fade is only allowed for privileged
               clients */
            instance->FadeChildren();
        break;
    }
}

void
BpInstance::OnControlPacket(ControlServer &_control_server,
                            enum beng_control_command command,
                            const void *payload, size_t payload_length,
                            SocketAddress address)
{
    handle_control_packet(this, &_control_server,
                          command, payload, payload_length,
                          address);
}

void
BpInstance::OnControlError(std::exception_ptr ep)
{
    daemon_log(2, "%s\n", GetFullMessage(ep).c_str());
}

void
global_control_handler_init(BpInstance *instance)
{
    if (instance->config.control_listen.empty())
        return;

    instance->control_distribute = new ControlDistribute(instance->event_loop,
                                                         *instance);

    for (const auto &control_listen : instance->config.control_listen) {
        instance->control_servers.emplace_front(instance->event_loop,
                                                *instance->control_distribute,
                                                control_listen);
    }
}

void
global_control_handler_deinit(BpInstance *instance)
{
    instance->control_servers.clear();
    delete instance->control_distribute;
}

void
global_control_handler_enable(BpInstance &instance)
{
    for (auto &c : instance.control_servers)
        c.Enable();
}

void
global_control_handler_disable(BpInstance &instance)
{
    for (auto &c : instance.control_servers)
        c.Disable();
}

UniqueSocketDescriptor
global_control_handler_add_fd(BpInstance *instance)
{
    assert(!instance->control_servers.empty());
    assert(instance->control_distribute != nullptr);

    return instance->control_distribute->Add();
}

void
global_control_handler_set_fd(BpInstance *instance,
                              UniqueSocketDescriptor &&fd)
{
    assert(!instance->control_servers.empty());
    assert(instance->control_distribute != nullptr);

    instance->control_distribute->Clear();

    /* erase all but one */
    instance->control_servers.erase_after(instance->control_servers.begin(),
                                          instance->control_servers.end());

    /* replace the one */
    instance->control_servers.front().SetFd(std::move(fd));
}

/*
 * local (implicit) control channel
 */

void
local_control_handler_init(BpInstance *instance)
{
    instance->local_control_server =
        control_local_new("beng_control:pid=", *instance);
}

void
local_control_handler_deinit(BpInstance *instance)
{
    control_local_free(instance->local_control_server);
}

void
local_control_handler_open(BpInstance *instance)
{
    control_local_open(instance->local_control_server,
                       instance->event_loop);
}
<commit_msg>bp_control: use the Logger library instead of libdaemon<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "bp_control.hxx"
#include "bp_stats.hxx"
#include "control_distribute.hxx"
#include "control_server.hxx"
#include "control_local.hxx"
#include "bp_instance.hxx"
#include "translation/Request.hxx"
#include "translation/Cache.hxx"
#include "translation/Protocol.hxx"
#include "translation/InvalidateParser.hxx"
#include "tpool.hxx"
#include "pool.hxx"
#include "net/UdpDistribute.hxx"
#include "net/SocketAddress.hxx"
#include "net/IPv4Address.hxx"
#include "io/Logger.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Exception.hxx"
#include "util/Macros.hxx"

#include <assert.h>
#include <string.h>

static void
control_tcache_invalidate(BpInstance *instance,
                          const void *payload, size_t payload_length)
{
    if (payload_length == 0) {
        /* flush the translation cache if the payload is empty */
        translate_cache_flush(*instance->translate_cache);
        return;
    }

    const AutoRewindPool auto_rewind(*tpool);

    TranslationInvalidateRequest request;

    try {
        request = ParseTranslationInvalidateRequest(*tpool,
                                                    payload, payload_length);
    } catch (...) {
        LogConcat(2, "control",
                  "malformed TCACHE_INVALIDATE control packet: ",
                  std::current_exception());
        return;
    }

    translate_cache_invalidate(*instance->translate_cache, request,
                               ConstBuffer<TranslationCommand>(request.commands.raw(),
                                                               request.commands.size()),
                               request.site);
}

static void
query_stats(BpInstance *instance, ControlServer *server,
            SocketAddress address)
{
    if (address.GetSize() == 0)
        /* TODO: this packet was forwarded by the master process, and
           has no source address; however, the master process must get
           statistics from all worker processes (even those that have
           exited already) */
        return;

    struct beng_control_stats stats;
    bp_get_stats(instance, &stats);

    try {
        server->Reply(address,
                      CONTROL_STATS, &stats, sizeof(stats));
    } catch (...) {
        LogConcat(3, "control", std::current_exception());
    }
}

static void
handle_control_packet(BpInstance *instance, ControlServer *server,
                      enum beng_control_command command,
                      const void *payload, size_t payload_length,
                      SocketAddress address)
{
    LogConcat(5, "control", "command=", int(command),
              " payload_length=", unsigned(payload_length));

    /* only local clients are allowed to use most commands */
    const bool is_privileged = address.GetFamily() == AF_LOCAL;

    switch (command) {
    case CONTROL_NOP:
        /* duh! */
        break;

    case CONTROL_TCACHE_INVALIDATE:
        control_tcache_invalidate(instance, payload, payload_length);
        break;

    case CONTROL_DUMP_POOLS:
        if (is_privileged)
            pool_dump_tree(instance->root_pool);
        break;

    case CONTROL_ENABLE_NODE:
    case CONTROL_FADE_NODE:
    case CONTROL_NODE_STATUS:
        /* only for beng-lb */
        break;

    case CONTROL_STATS:
        query_stats(instance, server, address);
        break;

    case CONTROL_VERBOSE:
        if (is_privileged && payload_length == 1)
            SetLogLevel(*(const uint8_t *)payload);
        break;

    case CONTROL_FADE_CHILDREN:
        if (payload_length > 0)
            /* tagged fade is allowed for any unprivileged client */
            instance->FadeTaggedChildren(std::string((const char *)payload,
                                                     payload_length).c_str());
        else if (is_privileged)
            /* unconditional fade is only allowed for privileged
               clients */
            instance->FadeChildren();
        break;
    }
}

void
BpInstance::OnControlPacket(ControlServer &_control_server,
                            enum beng_control_command command,
                            const void *payload, size_t payload_length,
                            SocketAddress address)
{
    handle_control_packet(this, &_control_server,
                          command, payload, payload_length,
                          address);
}

void
BpInstance::OnControlError(std::exception_ptr ep)
{
    LogConcat(2, "control", ep);
}

void
global_control_handler_init(BpInstance *instance)
{
    if (instance->config.control_listen.empty())
        return;

    instance->control_distribute = new ControlDistribute(instance->event_loop,
                                                         *instance);

    for (const auto &control_listen : instance->config.control_listen) {
        instance->control_servers.emplace_front(instance->event_loop,
                                                *instance->control_distribute,
                                                control_listen);
    }
}

void
global_control_handler_deinit(BpInstance *instance)
{
    instance->control_servers.clear();
    delete instance->control_distribute;
}

void
global_control_handler_enable(BpInstance &instance)
{
    for (auto &c : instance.control_servers)
        c.Enable();
}

void
global_control_handler_disable(BpInstance &instance)
{
    for (auto &c : instance.control_servers)
        c.Disable();
}

UniqueSocketDescriptor
global_control_handler_add_fd(BpInstance *instance)
{
    assert(!instance->control_servers.empty());
    assert(instance->control_distribute != nullptr);

    return instance->control_distribute->Add();
}

void
global_control_handler_set_fd(BpInstance *instance,
                              UniqueSocketDescriptor &&fd)
{
    assert(!instance->control_servers.empty());
    assert(instance->control_distribute != nullptr);

    instance->control_distribute->Clear();

    /* erase all but one */
    instance->control_servers.erase_after(instance->control_servers.begin(),
                                          instance->control_servers.end());

    /* replace the one */
    instance->control_servers.front().SetFd(std::move(fd));
}

/*
 * local (implicit) control channel
 */

void
local_control_handler_init(BpInstance *instance)
{
    instance->local_control_server =
        control_local_new("beng_control:pid=", *instance);
}

void
local_control_handler_deinit(BpInstance *instance)
{
    control_local_free(instance->local_control_server);
}

void
local_control_handler_open(BpInstance *instance)
{
    control_local_open(instance->local_control_server,
                       instance->event_loop);
}
<|endoftext|>


<commit_before>// -*-Mode: C++;-*-

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// -----------------------------------
// Part of HPCToolkit (hpctoolkit.org)
// -----------------------------------
//
// Copyright ((c)) 2002-2010, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

//***************************************************************************

//************************* System Include Files ****************************

#include <sys/param.h>

#include <cstdlib> // for 'mkstemp' (not technically visible in C++)
#include <cstdio>  // for 'tmpnam', 'rename'
#include <cerrno>
#include <cstdarg>
#include <cstring>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <fnmatch.h>

#include <string>
using std::string;

//*************************** User Include Files ****************************

#include "FileUtil.hpp"

#include "diagnostics.h"
#include "StrUtil.hpp"
#include "Trace.hpp"

//*************************** Forward Declarations **************************

using std::endl;

//***************************************************************************
//
//***************************************************************************

namespace FileUtil {

string
basename(const char* fName)
{
  string baseFileName;

  const char* lastSlash = strrchr(fName, '/');
  if (lastSlash) {
    // valid: "/foo" || ".../foo" AND invalid: "/" || ".../"
    baseFileName = lastSlash + 1;
  }
  else {
    // filename contains no slashes, already in short form
    baseFileName = fName;
  }
  return baseFileName;

#if 0
  // A "more C++" implementation (Gaurav)
  std::string
  PathFindMgr::getFileName(const std::string& path) const
  {
    size_t in = path.find_last_of("/");
    if (in != path.npos && path.length() > 1)
      return path.substr(in + 1);

    return path;
  }
#endif
}

string
rmSuffix(const char* fName)
{
  string baseFileName = fName;

  size_t pos = baseFileName.find_last_of('.');
  if (pos != string::npos) {
    baseFileName = baseFileName.substr(0, pos);
  }
  return baseFileName;
}

string
dirname(const char* fName)
{
  const char* lastSlash = strrchr(fName, '/');
  string pathComponent = ".";
  if (lastSlash) {
    pathComponent = fName;
    pathComponent.resize(lastSlash - fName);
  }
  return pathComponent;
}

bool
fnmatch(const std::vector<std::string>& patternVec,
	const char* string, int flags)
{
  for (uint i = 0; i < patternVec.size(); ++i) {
    const std::string& pat = patternVec[i];
    bool fnd = FileUtil::fnmatch(pat, string, flags);
    if (fnd) {
      return true;
    }
  }

  return false;
}

} // end of FileUtil namespace

//***************************************************************************
//
//***************************************************************************

namespace FileUtil {

bool
isReadable(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return true; // the file is readable
  }
  return false;
}

bool
isDir(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return (S_ISDIR(sbuf.st_mode)
	    /*|| S_ISLNK(sbuf.st_mode) && isDir(readlink(path))*/);
  }
  return false; // unknown
}

int
countChar(const char* path, char c)
{
  int srcFd = open(path, O_RDONLY);
  if (srcFd < 0) {
    return -1;
  }
  int count = 0;
  char buf[256];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, 256)) > 0) {
    for (int i = 0; i < nRead; i++) {
      if (buf[i] == c) count++;
    }
  }
  return count;
}

} // end of FileUtil namespace

//***************************************************************************
//
//***************************************************************************

static void
cpy(int srcFd, int dstFd)
{
  static const int bufSz = 4096;
  char buf[bufSz];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, bufSz)) > 0) {
    write(dstFd, buf, nRead);
  }
}

namespace FileUtil {

void
copy(const char* dst, ...)
{
  va_list srcFnmList;
  va_start(srcFnmList, dst);

  DIAG_MsgIf(0, "FileUtil::copy: ... -> " << dst);

  int dstFd = open(dst, O_WRONLY | O_CREAT | O_TRUNC,
		   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  if (dstFd < 0) {
    DIAG_Throw("could not open destination '" << dst << "' ("
	       << strerror(errno) << ")");
  }

  string errorMsg;

  char* srcFnm;
  while ( (srcFnm = va_arg(srcFnmList, char*)) ) {
    int srcFd = open(srcFnm, O_RDONLY);
    if ((srcFd < 0) || (dstFd < 0)) {
      errorMsg += (string("could not open '") + srcFnm + "' ("
		   + strerror(errno) + ")");
    }
    else {
      cpy(srcFd, dstFd);
      close(srcFd);
    }
  }

  va_end(srcFnmList);
  close(dstFd);

  if (!errorMsg.empty()) {
    DIAG_Throw("could not open source files: " << errorMsg);
  }
}

void
move(const char* dst, const char* src)
{
  int ret = rename(src, dst);
  if (ret != 0) {
    DIAG_Throw("moving '" << src << "' -> '" << dst << "'");
  }
}

int
remove(const char* file)
{
  return unlink(file);
}

int
mkdir(const char* dir)
{
  if (!dir) {
    DIAG_Throw("Invalid mkdir argument: (NULL)");
  }

  string pathStr = dir;
  bool isAbsPath = (dir[0] == '/');

  // -------------------------------------------------------
  // 1. Convert path string to vector of path components
  //    "/p0/p1/p2/.../pn/px" ==> [p0 p1 p2 ... pn px]
  //    "/p0"                 ==> [p0]
  //    "p0"                  ==> [p0]
  //    "./p0"                ==> [. p0]
  //
  // Note: we could do tokenization in place (string::find_last_of()),
  // but (1) this is more elegant and (2) sytem calls and disk
  // accesses will overwhelm any possible difference in performance.
  // -------------------------------------------------------
  std::vector<string> pathVec;
  StrUtil::tokenize_char(pathStr, "/", pathVec);

  DIAG_Assert(!pathVec.empty(), DIAG_UnexpectedInput);

  // -------------------------------------------------------
  // 2. Find 'curIdx' such that all paths before pathVec[curIdx] have
  // been created.
  //
  // Note: Start search from the last path component, assuming that in
  // the common case, intermediate directories are already created.
  //
  // Note: Could make this a binary search, but it would likely have
  // insignificant effects.
  // -------------------------------------------------------
  size_t begIdx = 0;
  size_t endIdx = pathVec.size() - 1;

  size_t curIdx = endIdx;
  for ( ; curIdx >= begIdx; --curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    if (isDir(x)) {
      break; // FIXME: double check: what if this is a symlink?
    }
  }

  curIdx++;

  // -------------------------------------------------------
  // 3. Build directories from pathVec[curIdx ... endIdx]
  // -------------------------------------------------------
  mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  for ( ; curIdx <= endIdx; ++curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    int ret = ::mkdir(x.c_str(), mode);
    if (ret != 0) {
      DIAG_Throw("While mkdir-ing '" << pathStr << "': Could not mkdir '"
		 << x << "' (" << strerror(errno) << ")");
    }
  }

  return 0;
}

std::pair<string, bool>
mkdirUnique(const char* dirnm)
{
  string dirnm_new = dirnm;
  bool is_done = false;

  mode_t mkmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  int ret = ::mkdir(dirnm, mkmode);
  if (ret == -1) {
    if (errno == EEXIST) {
      // attempt to create dirnm+pid;
      pid_t pid = getpid();
      string pid_str = StrUtil::toStr(pid);
      dirnm_new = dirnm_new + "-" + pid_str;
      DIAG_Msg(1, "Directory '" << dirnm << "' already exists. Trying " << dirnm_new);
      ret = ::mkdir(dirnm_new.c_str(), mkmode);
      if (ret == -1) {
	DIAG_Die("Could not create alternate directory " << dirnm_new);
      }
      else {
	DIAG_Msg(1, "Created directory: " << dirnm_new);
	is_done = true;
      }
    }
    else {
      DIAG_Die("Could not create database directory " << dirnm);
    }
  }

  return make_pair(dirnm_new, is_done);
}

const char*
tmpname()
{
  // below is a hack to replace the deprecated tmpnam which g++ 3.2.2 will
  // no longer allow. the mkstemp routine, which is touted as the replacement
  // for tmpnam, provides a file descriptor as a return value. there is
  // unfortunately no way to interface this with the ofstream class constructor
  // which requires a filename. thus, a hack is born ...
  // John Mellor-Crummey 5/7/2003

  // eraxxon: GNU is right that 'tmpnam' can be dangerous, but
  // 'mkstemp' is not strictly part of C++! We could create an
  // interface to 'mkstemp' within a C file, but this is getting
  // cumbersome... and 'tmpnam' is not quite a WMD.

#ifdef __GNUC__
  static char tmpfilename[MAXPATHLEN];

  // creating a unique temp name with the new mkstemp interface now
  // requires opening, closing, and deleting a file when all we want
  // is the filename. sigh ...
  strcpy(tmpfilename,"/tmp/hpcviewtmpXXXXXX");
  close(mkstemp(tmpfilename));
  unlink(tmpfilename);

  return tmpfilename;
#else
  return tmpnam(NULL);
#endif
}

} // end of FileUtil namespace

<commit_msg>Tweak several error messages.<commit_after>// -*-Mode: C++;-*-

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// -----------------------------------
// Part of HPCToolkit (hpctoolkit.org)
// -----------------------------------
//
// Copyright ((c)) 2002-2010, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

//***************************************************************************

//************************* System Include Files ****************************

#include <sys/param.h>

#include <cstdlib> // for 'mkstemp' (not technically visible in C++)
#include <cstdio>  // for 'tmpnam', 'rename'
#include <cerrno>
#include <cstdarg>
#include <cstring>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <fnmatch.h>

#include <string>
using std::string;

//*************************** User Include Files ****************************

#include "FileUtil.hpp"

#include "diagnostics.h"
#include "StrUtil.hpp"
#include "Trace.hpp"

//*************************** Forward Declarations **************************

using std::endl;

//***************************************************************************
//
//***************************************************************************

namespace FileUtil {

string
basename(const char* fName)
{
  string baseFileName;

  const char* lastSlash = strrchr(fName, '/');
  if (lastSlash) {
    // valid: "/foo" || ".../foo" AND invalid: "/" || ".../"
    baseFileName = lastSlash + 1;
  }
  else {
    // filename contains no slashes, already in short form
    baseFileName = fName;
  }
  return baseFileName;

#if 0
  // A "more C++" implementation (Gaurav)
  std::string
  PathFindMgr::getFileName(const std::string& path) const
  {
    size_t in = path.find_last_of("/");
    if (in != path.npos && path.length() > 1)
      return path.substr(in + 1);

    return path;
  }
#endif
}

string
rmSuffix(const char* fName)
{
  string baseFileName = fName;

  size_t pos = baseFileName.find_last_of('.');
  if (pos != string::npos) {
    baseFileName = baseFileName.substr(0, pos);
  }
  return baseFileName;
}

string
dirname(const char* fName)
{
  const char* lastSlash = strrchr(fName, '/');
  string pathComponent = ".";
  if (lastSlash) {
    pathComponent = fName;
    pathComponent.resize(lastSlash - fName);
  }
  return pathComponent;
}

bool
fnmatch(const std::vector<std::string>& patternVec,
	const char* string, int flags)
{
  for (uint i = 0; i < patternVec.size(); ++i) {
    const std::string& pat = patternVec[i];
    bool fnd = FileUtil::fnmatch(pat, string, flags);
    if (fnd) {
      return true;
    }
  }

  return false;
}

} // end of FileUtil namespace

//***************************************************************************
//
//***************************************************************************

namespace FileUtil {

bool
isReadable(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return true; // the file is readable
  }
  return false;
}

bool
isDir(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return (S_ISDIR(sbuf.st_mode)
	    /*|| S_ISLNK(sbuf.st_mode) && isDir(readlink(path))*/);
  }
  return false; // unknown
}

int
countChar(const char* path, char c)
{
  int srcFd = open(path, O_RDONLY);
  if (srcFd < 0) {
    return -1;
  }
  int count = 0;
  char buf[256];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, 256)) > 0) {
    for (int i = 0; i < nRead; i++) {
      if (buf[i] == c) count++;
    }
  }
  return count;
}

} // end of FileUtil namespace

//***************************************************************************
//
//***************************************************************************

static void
cpy(int srcFd, int dstFd)
{
  static const int bufSz = 4096;
  char buf[bufSz];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, bufSz)) > 0) {
    write(dstFd, buf, nRead);
  }
}

namespace FileUtil {

void
copy(const char* dst, ...)
{
  va_list srcFnmList;
  va_start(srcFnmList, dst);

  DIAG_MsgIf(0, "FileUtil::copy: ... -> " << dst);

  int dstFd = open(dst, O_WRONLY | O_CREAT | O_TRUNC,
		   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  if (dstFd < 0) {
    DIAG_Throw("[FileUtil::copy] could not open destination file '"
	       << dst << "' (" << strerror(errno) << ")");
  }

  string errorMsg;

  char* srcFnm;
  while ( (srcFnm = va_arg(srcFnmList, char*)) ) {
    int srcFd = open(srcFnm, O_RDONLY);
    if ((srcFd < 0) || (dstFd < 0)) {
      errorMsg += (string("could not open '") + srcFnm + "' ("
		   + strerror(errno) + ")");
    }
    else {
      cpy(srcFd, dstFd);
      close(srcFd);
    }
  }

  va_end(srcFnmList);
  close(dstFd);

  if (!errorMsg.empty()) {
    DIAG_Throw("[FileUtil::copy] could not open source files: " << errorMsg);
  }
}

void
move(const char* dst, const char* src)
{
  int ret = rename(src, dst);
  if (ret != 0) {
    DIAG_Throw("[FileUtil::move] '" << src << "' -> '" << dst << "'");
  }
}

int
remove(const char* file)
{
  return unlink(file);
}

int
mkdir(const char* dir)
{
  if (!dir) {
    DIAG_Throw("Invalid mkdir argument: (NULL)");
  }

  string pathStr = dir;
  bool isAbsPath = (dir[0] == '/');

  // -------------------------------------------------------
  // 1. Convert path string to vector of path components
  //    "/p0/p1/p2/.../pn/px" ==> [p0 p1 p2 ... pn px]
  //    "/p0"                 ==> [p0]
  //    "p0"                  ==> [p0]
  //    "./p0"                ==> [. p0]
  //
  // Note: we could do tokenization in place (string::find_last_of()),
  // but (1) this is more elegant and (2) sytem calls and disk
  // accesses will overwhelm any possible difference in performance.
  // -------------------------------------------------------
  std::vector<string> pathVec;
  StrUtil::tokenize_char(pathStr, "/", pathVec);

  DIAG_Assert(!pathVec.empty(), DIAG_UnexpectedInput);

  // -------------------------------------------------------
  // 2. Find 'curIdx' such that all paths before pathVec[curIdx] have
  // been created.
  //
  // Note: Start search from the last path component, assuming that in
  // the common case, intermediate directories are already created.
  //
  // Note: Could make this a binary search, but it would likely have
  // insignificant effects.
  // -------------------------------------------------------
  size_t begIdx = 0;
  size_t endIdx = pathVec.size() - 1;

  size_t curIdx = endIdx;
  for ( ; curIdx >= begIdx; --curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    if (isDir(x)) {
      break; // FIXME: double check: what if this is a symlink?
    }
  }

  curIdx++;

  // -------------------------------------------------------
  // 3. Build directories from pathVec[curIdx ... endIdx]
  // -------------------------------------------------------
  mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  for ( ; curIdx <= endIdx; ++curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    int ret = ::mkdir(x.c_str(), mode);
    if (ret != 0) {
      DIAG_Throw("[FileUtil::mkdir] '" << pathStr << "': Could not mkdir '"
		 << x << "' (" << strerror(errno) << ")");
    }
  }

  return 0;
}

std::pair<string, bool>
mkdirUnique(const char* dirnm)
{
  string dirnm_new = dirnm;
  bool is_done = false;

  mode_t mkmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  int ret = ::mkdir(dirnm, mkmode);
  if (ret == -1) {
    if (errno == EEXIST) {
      // attempt to create dirnm+pid;
      pid_t pid = getpid();
      string pid_str = StrUtil::toStr(pid);
      dirnm_new = dirnm_new + "-" + pid_str;
      DIAG_Msg(1, "Directory '" << dirnm << "' already exists. Trying " << dirnm_new);
      ret = ::mkdir(dirnm_new.c_str(), mkmode);
      if (ret == -1) {
	DIAG_Die("Could not create alternate directory " << dirnm_new);
      }
      else {
	DIAG_Msg(1, "Created directory: " << dirnm_new);
	is_done = true;
      }
    }
    else {
      DIAG_Die("Could not create database directory " << dirnm);
    }
  }

  return make_pair(dirnm_new, is_done);
}

const char*
tmpname()
{
  // below is a hack to replace the deprecated tmpnam which g++ 3.2.2 will
  // no longer allow. the mkstemp routine, which is touted as the replacement
  // for tmpnam, provides a file descriptor as a return value. there is
  // unfortunately no way to interface this with the ofstream class constructor
  // which requires a filename. thus, a hack is born ...
  // John Mellor-Crummey 5/7/2003

  // eraxxon: GNU is right that 'tmpnam' can be dangerous, but
  // 'mkstemp' is not strictly part of C++! We could create an
  // interface to 'mkstemp' within a C file, but this is getting
  // cumbersome... and 'tmpnam' is not quite a WMD.

#ifdef __GNUC__
  static char tmpfilename[MAXPATHLEN];

  // creating a unique temp name with the new mkstemp interface now
  // requires opening, closing, and deleting a file when all we want
  // is the filename. sigh ...
  strcpy(tmpfilename,"/tmp/hpcviewtmpXXXXXX");
  close(mkstemp(tmpfilename));
  unlink(tmpfilename);

  return tmpfilename;
#else
  return tmpnam(NULL);
#endif
}

} // end of FileUtil namespace

<|endoftext|>