<commit_before>/*
 * OptimalSolver.cpp
 *
 *  Created on: 2015-05-16
 *      Author: legraina
 */

#include "main_test.h"
#include "MyTools.h"

// n030w4 1 4 6 2 9 1 n030w4_1_6-2-9-1
// Function for solving the optimal solution
int main(int argc, char** argv)
{
	std::cout << "# Launching Optimal Roster..." << std::endl;

   int locINT;

   int k = 0;

   string inst = argv[++k];

   std::istringstream(argv[++k]) >> locINT;
   int historyID = locINT;

   std::istringstream(argv[++k]) >> locINT;
   int nbWeeks = locINT;
   if(5+nbWeeks > argc)
      Tools::throwError("Bad input format. Should be: instance_name historyID numberWeeks vector<int>weekIndices outdir prefix numberTest solver_options generation_options evaluations_options. After outdir, the arguments are optional.");

   vector<int> numberWeek;
   for(int i=0; i<nbWeeks; ++i){
      std::istringstream(argv[++k]) >> locINT;
      numberWeek.push_back(locINT);
   }

   string outdir = argv[++k];

   int givenSeed;
   if(k+1 < argc){
	      std::istringstream(argv[++k]) >> locINT;
	      givenSeed = locINT;
   }

   int nbEval;
   if(k+1 < argc){
	      std::istringstream(argv[++k]) >> locINT;
	      nbEval = locINT;
   }

   string prefix = "";
   if(k+1 < argc)
        prefix = argv[++k];

   string data = "datasets/";
   string scenarPath = data + inst + "/Sc-" + inst + ".txt";
   string outpath = "outfiles/Competition/"+outdir+"/"+prefix;
   string outfile = outpath+"sol-week";
   string logfile = outpath+"Log.txt";
   string optionspath = data+"optionFiles/";

   string stoOptionsFile = optionspath+"stochastic_solver.txt";
   string geneOptionsFile = optionspath+"generation_solver.txt";
   string evaOptionsFile = optionspath+"evaluation_solver.txt";

   // Time the complete execution of the algorithm
   Tools::Timer* timertotal = new Tools::Timer();
   timertotal->init();
   timertotal->start();

//   SolverParam optParam;
//   optParam.printEverySolution_ = true;
//   optParam.weekIndices_ = numberWeek;
//   optParam.outfile_ = outfile;
//   optParam.logfile_ = logfile;
//   optParam.solveToOptimality_ = true;
//   optParam.nbDiveIfMinGap_ = 2;
//   optParam.nbDiveIfRelGap_ = 8;
//   testMultipleWeeksDeterministic(data, inst, historyID, numberWeek, GENCOL, "outfiles/Competition/"+outdir+"/"+prefix, optParam);

   srand(givenSeed);
   int seed = rand();

   pair<double, int> p;

   /*
    * Block for RK_SCORE
    */

//   StochasticSolverOptions stochasticSolverOptionsScore;
//   setStochasticSolverOptions(stochasticSolverOptionsScore, SUNGRID, inst, outfile, outpath,
//		   stoOptionsFile, geneOptionsFile, evaOptionsFile);
//
//   p = testMultipleWeeksStochastic(data, inst, historyID, numberWeek, stochasticSolverOptionsScore, outpath+"score_", seed);
//
//   char results[250];
//   sprintf(results, "Seed %d; Cost %.2f; NbGene %d; NbEval %d; WeightStrat %d; RankStrat %d;  nbDaysGeneration %d; nbDaysEvaluation %d;",
//		   seed, p.first, p.second, stochasticSolverOptionsScore.nEvaluationDemands_,
//		   stochasticSolverOptionsScore.generationParameters_.weightStrategy_, stochasticSolverOptionsScore.rankingStrategy_,
//		   7+stochasticSolverOptionsScore.nExtraDaysGenerationDemands_, stochasticSolverOptionsScore.nDaysEvaluation_);
//   string sensibilityOutfile = outpath+"score_sensibility.txt";
//   Tools::LogOutput sensibilityStream(sensibilityOutfile, true);
//   sensibilityStream << results << std::endl;
//

   /*
    * Block for RK_MEAN
    */

   StochasticSolverOptions stochasticSolverOptionsMean;
   setStochasticSolverOptions(stochasticSolverOptionsMean, SUNGRID, inst, outfile, outpath,
		   stoOptionsFile, geneOptionsFile, evaOptionsFile);

   stochasticSolverOptionsMean.rankingStrategy_ = RK_MEAN;

   p = testMultipleWeeksStochastic(data, inst, historyID, numberWeek, stochasticSolverOptionsMean, outpath+"mean_", seed);

   char results2[250];
   sprintf(results2, "Seed %d; Cost %.2f; NbGene %d; NbEval %d; WeightStrat %d; RankStrat %d;  nbDaysGeneration %d; nbDaysEvaluation %d;",
		   seed, p.first, p.second, stochasticSolverOptionsMean.nEvaluationDemands_,
		   stochasticSolverOptionsMean.generationParameters_.weightStrategy_, stochasticSolverOptionsMean.rankingStrategy_,
		   7+stochasticSolverOptionsMean.nExtraDaysGenerationDemands_, stochasticSolverOptionsMean.nDaysEvaluation_);
   string sensibilityOutfile2 = outpath+"mean_sensibility.txt";
   Tools::LogOutput sensibilityStream2(sensibilityOutfile2, true);
   sensibilityStream2 << results2 << std::endl;

   // Display the total time spent in the algorithm
   timertotal->stop();
   std::cout << "Total time spent in the algorithm : " << timertotal->dSinceInit() << std::endl;

   // free the allocated pointers
   //
   delete timertotal;

//vector<string> instances =
//{
//   "n030w4_1_6-2-9-1", "n030w4_1_6-7-5-3", "n030w8_1_2-7-0-9-3-6-0-6", "n030w8_1_6-7-5-3-5-6-2-9",
//   "n040w4_0_2-0-6-1", "n040w4_2_6-1-0-6", "n040w8_0_0-6-8-9-2-6-6-4", "n040w8_2_5-0-4-8-7-1-7-2",
//   "n050w4_0_0-4-8-7", "n050w4_0_7-2-7-2", "n050w8_1_1-7-8-5-7-4-1-8", "n050w8_1_9-7-5-3-8-8-3-1",
//   "n060w4_1_6-1-1-5", "n060w4_1_9-6-3-8", "n060w8_0_6-2-9-9-0-8-1-3", "n060w8_2_1-0-3-4-0-3-9-1",
//   "n080w4_2_4-3-3-3", "n080w4_2_6-0-4-8", "n080w8_1_4-4-9-9-3-6-0-5", "n080w8_2_0-4-0-9-1-9-6-2",
//   "n100w4_0_1-1-0-8", "n100w4_2_0-6-4-6", "n100w8_0_0-1-7-8-9-1-5-4", "n100w8_1_2-4-7-9-3-9-2-8",
//   "n120w4_1_4-6-2-6", "n120w4_1_5-6-9-8", "n120w8_0_0-9-9-4-5-1-0-3", "n120w8_1_7-2-6-4-5-2-0-2"
//};

}
<commit_msg>AL haaaaaaaaagggghhhhhh<commit_after>/*
 * OptimalSolver.cpp
 *
 *  Created on: 2015-05-16
 *      Author: legraina
 */

#include "main_test.h"
#include "MyTools.h"

// n030w4 1 4 6 2 9 1 n030w4_1_6-2-9-1
// Function for solving the optimal solution
int main(int argc, char** argv)
{
	std::cout << "# Launching Optimal Roster..." << std::endl;

   int locINT;

   int k = 0;

   string inst = argv[++k];

   std::istringstream(argv[++k]) >> locINT;
   int historyID = locINT;

   std::istringstream(argv[++k]) >> locINT;
   int nbWeeks = locINT;
   if(5+nbWeeks > argc)
      Tools::throwError("Bad input format. Should be: instance_name historyID numberWeeks vector<int>weekIndices outdir prefix numberTest solver_options generation_options evaluations_options. After outdir, the arguments are optional.");

   vector<int> numberWeek;
   for(int i=0; i<nbWeeks; ++i){
      std::istringstream(argv[++k]) >> locINT;
      numberWeek.push_back(locINT);
   }

   string outdir = argv[++k];

   int givenSeed;
   if(k+1 < argc){
	      std::istringstream(argv[++k]) >> locINT;
	      givenSeed = locINT;
   }

   int nbEval;
   if(k+1 < argc){
	      std::istringstream(argv[++k]) >> locINT;
	      nbEval = locINT;
   }

   string prefix = "";
   if(k+1 < argc)
        prefix = argv[++k];

   string data = "datasets/";
   string scenarPath = data + inst + "/Sc-" + inst + ".txt";
   string outpath = "outfiles/Competition/"+outdir+"/"+prefix;
   string outfile = outpath+"sol-week";
   string logfile = outpath+"Log.txt";
   string optionspath = data+"optionFiles/";

   string stoOptionsFile = optionspath+"stochastic_solver.txt";
   string geneOptionsFile = optionspath+"generation_solver.txt";
   string evaOptionsFile = optionspath+"evaluation_solver.txt";

   // Time the complete execution of the algorithm
   Tools::Timer* timertotal = new Tools::Timer();
   timertotal->init();
   timertotal->start();

//   SolverParam optParam;
//   optParam.printEverySolution_ = true;
//   optParam.weekIndices_ = numberWeek;
//   optParam.outfile_ = outfile;
//   optParam.logfile_ = logfile;
//   optParam.solveToOptimality_ = true;
//   optParam.nbDiveIfMinGap_ = 2;
//   optParam.nbDiveIfRelGap_ = 8;
//   testMultipleWeeksDeterministic(data, inst, historyID, numberWeek, GENCOL, "outfiles/Competition/"+outdir+"/"+prefix, optParam);

   srand(givenSeed);
   int seed = rand();

   pair<double, int> p;

   /*
    * Block for RK_SCORE
    */

//   StochasticSolverOptions stochasticSolverOptionsScore;
//   setStochasticSolverOptions(stochasticSolverOptionsScore, SUNGRID, inst, outfile, outpath,
//		   stoOptionsFile, geneOptionsFile, evaOptionsFile);
//
//   stochasticSolverOptionsScore.nEvaluationDemands_ = nbEval;
//   p = testMultipleWeeksStochastic(data, inst, historyID, numberWeek, stochasticSolverOptionsScore, outpath+"score_", seed);
//
//   char results[250];
//   sprintf(results, "Seed %d; Cost %.2f; NbGene %d; NbEval %d; WeightStrat %d; RankStrat %d;  nbDaysGeneration %d; nbDaysEvaluation %d;",
//		   seed, p.first, p.second, stochasticSolverOptionsScore.nEvaluationDemands_,
//		   stochasticSolverOptionsScore.generationParameters_.weightStrategy_, stochasticSolverOptionsScore.rankingStrategy_,
//		   7+stochasticSolverOptionsScore.nExtraDaysGenerationDemands_, stochasticSolverOptionsScore.nDaysEvaluation_);
//   string sensibilityOutfile = outpath+"score_sensibility.txt";
//   Tools::LogOutput sensibilityStream(sensibilityOutfile, true);
//   sensibilityStream << results << std::endl;
//

   /*
    * Block for RK_MEAN
    */

   StochasticSolverOptions stochasticSolverOptionsMean;
   setStochasticSolverOptions(stochasticSolverOptionsMean, SUNGRID, inst, outfile, outpath,
		   stoOptionsFile, geneOptionsFile, evaOptionsFile);

   stochasticSolverOptionsMean.nEvaluationDemands_ = nbEval;
   stochasticSolverOptionsMean.rankingStrategy_ = RK_MEAN;

   p = testMultipleWeeksStochastic(data, inst, historyID, numberWeek, stochasticSolverOptionsMean, outpath+"mean_", seed);

   char results2[250];
   sprintf(results2, "Seed %d; Cost %.2f; NbGene %d; NbEval %d; WeightStrat %d; RankStrat %d;  nbDaysGeneration %d; nbDaysEvaluation %d;",
		   seed, p.first, p.second, stochasticSolverOptionsMean.nEvaluationDemands_,
		   stochasticSolverOptionsMean.generationParameters_.weightStrategy_, stochasticSolverOptionsMean.rankingStrategy_,
		   7+stochasticSolverOptionsMean.nExtraDaysGenerationDemands_, stochasticSolverOptionsMean.nDaysEvaluation_);
   string sensibilityOutfile2 = outpath+"mean_sensibility.txt";
   Tools::LogOutput sensibilityStream2(sensibilityOutfile2, true);
   sensibilityStream2 << results2 << std::endl;

   // Display the total time spent in the algorithm
   timertotal->stop();
   std::cout << "Total time spent in the algorithm : " << timertotal->dSinceInit() << std::endl;

   // free the allocated pointers
   //
   delete timertotal;

//vector<string> instances =
//{
//   "n030w4_1_6-2-9-1", "n030w4_1_6-7-5-3", "n030w8_1_2-7-0-9-3-6-0-6", "n030w8_1_6-7-5-3-5-6-2-9",
//   "n040w4_0_2-0-6-1", "n040w4_2_6-1-0-6", "n040w8_0_0-6-8-9-2-6-6-4", "n040w8_2_5-0-4-8-7-1-7-2",
//   "n050w4_0_0-4-8-7", "n050w4_0_7-2-7-2", "n050w8_1_1-7-8-5-7-4-1-8", "n050w8_1_9-7-5-3-8-8-3-1",
//   "n060w4_1_6-1-1-5", "n060w4_1_9-6-3-8", "n060w8_0_6-2-9-9-0-8-1-3", "n060w8_2_1-0-3-4-0-3-9-1",
//   "n080w4_2_4-3-3-3", "n080w4_2_6-0-4-8", "n080w8_1_4-4-9-9-3-6-0-5", "n080w8_2_0-4-0-9-1-9-6-2",
//   "n100w4_0_1-1-0-8", "n100w4_2_0-6-4-6", "n100w8_0_0-1-7-8-9-1-5-4", "n100w8_1_2-4-7-9-3-9-2-8",
//   "n120w4_1_4-6-2-6", "n120w4_1_5-6-9-8", "n120w8_0_0-9-9-4-5-1-0-3", "n120w8_1_7-2-6-4-5-2-0-2"
//};

}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cmath>

int main(){
    int n, a, b, c, d, r, num, den, num_r, den_r, j;
    char o, i;

    scanf("%d", &n);
    while(n--){
        scanf("%d %c %d %c %d %c %d", &a, &i, &b, &o, &c, &i, &d);
        if (o == '+'){
            num = (b * d) * a / b + (b * d) * c / d;
            den = b * d;
        } else if (o == '-'){
            num = (b * d) * a / b - (b * d) * c / d;
            den = b * d;
        } else if (o == '*'){
            num = a * c;
            den = b * d;
        } else {
            num = a * d;
            den = b * c;
        }

        if (std::abs(num) < std::abs(den))
            r = std::abs(num);
        else
            r = std::abs(den);

        num_r = num;
        den_r = den;

        j = 2;
        while (j <= r){
            if (num_r % j == 0 && den_r % j == 0){
                num_r = num_r / j;
                den_r = den_r / j;
            } else {
                j++;
            }
        }

        printf("%d/%d = %d/%d\n", num, den, num_r, den_r);
    }
    return 0;
}
<commit_msg>Pequena refatoração no 1022.<commit_after>#include <cstdio>
#include <cmath>

int main(){
    int n, a, b, c, d, r, num, den, num_r, den_r, j;
    char o, i;

    scanf("%d", &n);
    while(n--){
        scanf("%d %c %d %c %d %c %d", &a, &i, &b, &o, &c, &i, &d);
        if (o == '+'){
            num = (b * d) * a / b + (b * d) * c / d;
            den = b * d;
        } else if (o == '-'){
            num = (b * d) * a / b - (b * d) * c / d;
            den = b * d;
        } else if (o == '*'){
            num = a * c;
            den = b * d;
        } else {
            num = a * d;
            den = b * c;
        }

        if (std::abs(num) < std::abs(den))
            r = std::abs(num);
        else
            r = std::abs(den);

        num_r = num;
        den_r = den;

        j = 2;
        while (j <= r / 2 + 1){
            if (num_r % j == 0 && den_r % j == 0){
                num_r = num_r / j;
                den_r = den_r / j;
            } else {
                j++;
            }
        }

        printf("%d/%d = %d/%d\n", num, den, num_r, den_r);
    }
    return 0;
}
<|endoftext|>


<commit_before>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XX                                                                           XX
XX                              UnwindInfo                                   XX
XX                                                                           XX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*/

#include "jitpch.h"
#ifdef _MSC_VER
#pragma hdrstop
#endif

#if FEATURE_EH_FUNCLETS

//------------------------------------------------------------------------
// Compiler::unwindGetFuncLocations: Get the start/end emitter locations for this
// function or funclet. If 'getHotSectionData' is true, get the start/end locations
// for the hot section. Otherwise, get the data for the cold section.
//
// Note that we grab these locations before the prolog and epilogs are generated, so the
// locations must remain correct after the prolog and epilogs are generated.
//
// For the prolog, instructions are put in the special, preallocated, prolog instruction group.
// We don't want to expose the emitPrologIG unnecessarily (locations are actually pointers to
// emitter instruction groups). Since we know the offset of the start of the function/funclet,
// where the prolog is, will be zero, we use a nullptr start location to indicate that.
//
// There is no instruction group beyond the end of the end of the function, so there is no
// location to indicate that. Once again, use nullptr for that.
//
// Intermediate locations point at the first instruction group of a funclet, which is a
// placeholder IG. These are converted to real IGs, not deleted and replaced, so the location
// remains valid.
//
// Arguments:
//    func              - main function or funclet to get locations for.
//    getHotSectionData - 'true' to get the hot section data, 'false' to get the cold section data.
//    ppStartLoc        - OUT parameter. Set to the start emitter location.
//    ppEndLoc          - OUT parameter. Set to the end   emitter location (the location immediately
//                        the range; the 'end' location is not inclusive).
//
// Notes:
//    A start location of nullptr means the beginning of the code.
//    An end location of nullptr means the end of the code.
//
void Compiler::unwindGetFuncLocations(FuncInfoDsc*             func,
                                      bool                     getHotSectionData,
                                      /* OUT */ emitLocation** ppStartLoc,
                                      /* OUT */ emitLocation** ppEndLoc)
{
    if (func->funKind == FUNC_ROOT)
    {
        // Since all funclets are pulled out of line, the main code size is everything
        // up to the first handler. If the function is hot/cold split, we need to get the
        // appropriate sub-range.

        if (getHotSectionData)
        {
            *ppStartLoc = nullptr; // nullptr emit location means the beginning of the code. This is to handle the first
                                   // fragment prolog.

            if (fgFirstColdBlock != nullptr)
            {
                // The hot section only goes up to the cold section
                assert(fgFirstFuncletBB == nullptr);

                *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock));
            }
            else
            {
                if (fgFirstFuncletBB != nullptr)
                {
                    *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstFuncletBB));
                }
                else
                {
                    *ppEndLoc = nullptr; // nullptr end location means the end of the code
                }
            }
        }
        else
        {
            assert(fgFirstFuncletBB == nullptr); // TODO-CQ: support hot/cold splitting in functions with EH
            assert(fgFirstColdBlock != nullptr); // There better be a cold section!

            *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock));
            *ppEndLoc   = nullptr; // nullptr end location means the end of the code
        }
    }
    else
    {
        assert(getHotSectionData); // TODO-CQ: support funclets in cold section

        EHblkDsc* HBtab = ehGetDsc(func->funEHIndex);

        if (func->funKind == FUNC_FILTER)
        {
            assert(HBtab->HasFilter());
            *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdFilter));
            *ppEndLoc   = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndBeg));
        }
        else
        {
            assert(func->funKind == FUNC_HANDLER);
            *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndBeg));
            *ppEndLoc   = (HBtab->ebdHndLast->bbNext == nullptr)
                            ? nullptr
                            : new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndLast->bbNext));
        }
    }
}

#endif // FEATURE_EH_FUNCLETS

#if defined(_TARGET_UNIX_)

void Compiler::createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR cfiOpcode, USHORT dwarfReg, INT offset)
{
    CFI_CODE cfiEntry(codeOffset, cfiOpcode, dwarfReg, offset);
    func->cfiCodes->push_back(cfiEntry);
}

void Compiler::unwindPushCFI(regNumber reg)
{
    assert(compGeneratingProlog);

    FuncInfoDsc* func = funCurrentFunc();

    unsigned int cbProlog = unwindGetCurrentOffset(func);
    noway_assert((BYTE)cbProlog == cbProlog);

    createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, REGSIZE_BYTES == 8 ? 8 : 4);
    if ((RBM_CALLEE_SAVED & genRegMask(reg))
#if defined(UNIX_AMD64_ABI)
#if ETW_EBP_FRAMED
        // In case of ETW_EBP_FRAMED defined the REG_FPBASE (RBP)
        // is excluded from the callee-save register list.
        // Make sure the register gets PUSH unwind info in this case,
        // since it is pushed as a frame register.
        || (reg == REG_FPBASE)
#endif // ETW_EBP_FRAMED
#endif
            )
    {
        createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg));
    }
}

template <typename T>
inline static T* allocate_any(jitstd::allocator<void>& alloc, size_t count = 5)
{
    return jitstd::allocator<T>(alloc).allocate(count);
}

typedef jitstd::vector<CFI_CODE> CFICodeVector;

void Compiler::unwindBegPrologCFI()
{
    assert(compGeneratingProlog);

#if FEATURE_EH_FUNCLETS
    FuncInfoDsc* func = funCurrentFunc();

    // There is only one prolog for a function/funclet, and it comes first. So now is
    // a good time to initialize all the unwind data structures.

    unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);

    if (fgFirstColdBlock != nullptr)
    {
        unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
    }

    jitstd::allocator<void> allocator(getAllocator());

    func->cfiCodes = new (allocate_any<CFICodeVector>(allocator), jitstd::placement_t()) CFICodeVector(allocator);
#endif // FEATURE_EH_FUNCLETS
}

void Compiler::unwindPushMaskCFI(regMaskTP regMask, bool isFloat)
{
    regMaskTP regBit = isFloat ? genRegMask(REG_FP_FIRST) : 1;

    for (regNumber regNum = isFloat ? REG_FP_FIRST : REG_FIRST; regNum < REG_COUNT;
         regNum           = REG_NEXT(regNum), regBit <<= 1)
    {
        if (regBit > regMask)
        {
            break;
        }

        if (regBit & regMask)
        {
            unwindPushCFI(regNum);
        }
    }
}

void Compiler::unwindAllocStackCFI(unsigned size)
{
    assert(compGeneratingProlog);

    FuncInfoDsc* func = funCurrentFunc();

    unsigned int cbProlog = unwindGetCurrentOffset(func);
    noway_assert((BYTE)cbProlog == cbProlog);
    createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, size);
}

//------------------------------------------------------------------------
// Compiler::unwindSetFrameRegCFI: Record a cfi info for a frame register set.
//
// Arguments:
//    reg    - The register being set as the frame register.
//    offset - The offset from the current stack pointer that the frame pointer will point at.
//
void Compiler::unwindSetFrameRegCFI(regNumber reg, unsigned offset)
{
    assert(compGeneratingProlog);
    FuncInfoDsc* func = funCurrentFunc();

    unsigned int cbProlog = unwindGetCurrentOffset(func);
    noway_assert((BYTE)cbProlog == cbProlog);

    createCfiCode(func, cbProlog, CFI_DEF_CFA_REGISTER, mapRegNumToDwarfReg(reg));
    if (offset != 0)
    {
        // before: cfa = rsp + old_cfa_offset;
        //         rbp = rsp + offset;
        // after: cfa should be based on rbp, but points to the old address:
        //         rsp + old_cfa_offset == rbp + old_cfa_offset + adjust;
        // adjust = -offset;
        int adjust = -(int)offset;
        createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, adjust);
    }
}

void Compiler::unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdCode)
{
    UNATIVE_OFFSET startOffset;
    UNATIVE_OFFSET endOffset;
    DWORD          unwindCodeBytes = 0;
    BYTE*          pUnwindBlock    = nullptr;

    if (func->startLoc == nullptr)
    {
        startOffset = 0;
    }
    else
    {
        startOffset = func->startLoc->CodeOffset(genEmitter);
    }

    if (func->endLoc == nullptr)
    {
        endOffset = info.compNativeCodeSize;
    }
    else
    {
        endOffset = func->endLoc->CodeOffset(genEmitter);
    }

    DWORD size = (DWORD)func->cfiCodes->size();
    if (size > 0)
    {
        unwindCodeBytes = size * sizeof(CFI_CODE);
        pUnwindBlock    = (BYTE*)&(*func->cfiCodes)[0];
    }

#ifdef DEBUG
    if (opts.dspUnwind)
    {
        DumpCfiInfo(true /*isHotCode*/, startOffset, endOffset, unwindCodeBytes, (const CFI_CODE* const)pUnwindBlock);
    }
#endif // DEBUG

    assert(endOffset <= info.compTotalHotCodeSize);

    eeAllocUnwindInfo((BYTE*)pHotCode, nullptr /* pColdCode */, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
                      (CorJitFuncKind)func->funKind);

    if (pColdCode != NULL)
    {
        assert(fgFirstColdBlock != nullptr);
        assert(func->funKind == FUNC_ROOT); // No splitting of funclets.

        unwindCodeBytes = 0;
        pUnwindBlock    = nullptr;

        if (func->coldStartLoc == nullptr)
        {
            startOffset = 0;
        }
        else
        {
            startOffset = func->coldStartLoc->CodeOffset(genEmitter);
        }

        if (func->coldEndLoc == nullptr)
        {
            endOffset = info.compNativeCodeSize;
        }
        else
        {
            endOffset = func->coldEndLoc->CodeOffset(genEmitter);
        }

#ifdef DEBUG
        if (opts.dspUnwind)
        {
            DumpCfiInfo(false /*isHotCode*/, startOffset, endOffset, unwindCodeBytes,
                        (const CFI_CODE* const)pUnwindBlock);
        }
#endif // DEBUG

        assert(startOffset >= info.compTotalHotCodeSize);
        startOffset -= info.compTotalHotCodeSize;
        endOffset -= info.compTotalHotCodeSize;

        eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
                          (CorJitFuncKind)func->funKind);
    }
}

#ifdef DEBUG
//------------------------------------------------------------------------
// DumpCfiInfo: Dump the Cfi data.
//
// Arguments:
//    isHotCode   - true if this cfi data is for the hot section, false otherwise.
//    startOffset - byte offset of the code start that this cfi data represents.
//    endOffset   - byte offset of the code end   that this cfi data represents.
//    pcFiCode    - pointer to the cfi data blob.
//
void Compiler::DumpCfiInfo(bool                  isHotCode,
                           UNATIVE_OFFSET        startOffset,
                           UNATIVE_OFFSET        endOffset,
                           DWORD                 cfiCodeBytes,
                           const CFI_CODE* const pCfiCode)
{
    printf("Cfi Info%s:\n", isHotCode ? "" : " COLD");
    printf("  >> Start offset   : 0x%06x \n", dspOffset(startOffset));
    printf("  >>   End offset   : 0x%06x \n", dspOffset(endOffset));

    for (int i = 0; i < (int)(cfiCodeBytes / sizeof(CFI_CODE)); i++)
    {
        const CFI_CODE* const pCode = &(pCfiCode[i]);

        UCHAR codeOffset = pCode->CodeOffset;
        SHORT dwarfReg   = pCode->DwarfReg;
        INT   offset     = pCode->Offset;

        switch (pCode->CfiOpCode)
        {
            case CFI_REL_OFFSET:
                printf("    CodeOffset: 0x%02X Op: RelOffset DwarfReg:0x%x Offset:0x%X\n", codeOffset, dwarfReg,
                       offset);
                break;
            case CFI_DEF_CFA_REGISTER:
                assert(offset == 0);
                printf("    CodeOffset: 0x%02X Op: DefCfaRegister DwarfReg:0x%X\n", codeOffset, dwarfReg);
                break;
            case CFI_ADJUST_CFA_OFFSET:
                assert(dwarfReg == DWARF_REG_ILLEGAL);
                printf("    CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset);
                break;
            default:
                printf("    Unrecognized CFI_CODE: 0x%IX\n", *(UINT64*)pCode);
                break;
        }
    }
}
#endif // DEBUG

#endif // _TARGET_UNIX_

//------------------------------------------------------------------------
// Compiler::unwindGetCurrentOffset: Calculate the current byte offset of the
// prolog being generated.
//
// Arguments:
//    func - The main function or funclet of interest.
//
// Return Value:
//    The byte offset of the prolog currently being generated.
//
UNATIVE_OFFSET Compiler::unwindGetCurrentOffset(FuncInfoDsc* func)
{
    assert(compGeneratingProlog);
    UNATIVE_OFFSET offset;
    if (func->funKind == FUNC_ROOT)
    {
        offset = genEmitter->emitGetPrologOffsetEstimate();
    }
    else
    {
#if defined(_TARGET_AMD64_)
        assert(func->startLoc != nullptr);
        offset = func->startLoc->GetFuncletPrologOffset(genEmitter);
#else
        offset = 0; // TODO ???
#endif
    }

    return offset;
}

#if defined(_TARGET_AMD64_)

// See unwindAmd64.cpp

#elif defined(_TARGET_ARM64_)

// See unwindArm64.cpp

#elif defined(_TARGET_ARM_)

// See unwindArm.cpp

#elif defined(_TARGET_X86_)

// See unwindX86.cpp

#else // _TARGET_*

#error Unsupported or unset target architecture

#endif // _TARGET_*
<commit_msg>Fix jit fromatting<commit_after>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XX                                                                           XX
XX                              UnwindInfo                                   XX
XX                                                                           XX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*/

#include "jitpch.h"
#ifdef _MSC_VER
#pragma hdrstop
#endif

#if FEATURE_EH_FUNCLETS

//------------------------------------------------------------------------
// Compiler::unwindGetFuncLocations: Get the start/end emitter locations for this
// function or funclet. If 'getHotSectionData' is true, get the start/end locations
// for the hot section. Otherwise, get the data for the cold section.
//
// Note that we grab these locations before the prolog and epilogs are generated, so the
// locations must remain correct after the prolog and epilogs are generated.
//
// For the prolog, instructions are put in the special, preallocated, prolog instruction group.
// We don't want to expose the emitPrologIG unnecessarily (locations are actually pointers to
// emitter instruction groups). Since we know the offset of the start of the function/funclet,
// where the prolog is, will be zero, we use a nullptr start location to indicate that.
//
// There is no instruction group beyond the end of the end of the function, so there is no
// location to indicate that. Once again, use nullptr for that.
//
// Intermediate locations point at the first instruction group of a funclet, which is a
// placeholder IG. These are converted to real IGs, not deleted and replaced, so the location
// remains valid.
//
// Arguments:
//    func              - main function or funclet to get locations for.
//    getHotSectionData - 'true' to get the hot section data, 'false' to get the cold section data.
//    ppStartLoc        - OUT parameter. Set to the start emitter location.
//    ppEndLoc          - OUT parameter. Set to the end   emitter location (the location immediately
//                        the range; the 'end' location is not inclusive).
//
// Notes:
//    A start location of nullptr means the beginning of the code.
//    An end location of nullptr means the end of the code.
//
void Compiler::unwindGetFuncLocations(FuncInfoDsc*             func,
                                      bool                     getHotSectionData,
                                      /* OUT */ emitLocation** ppStartLoc,
                                      /* OUT */ emitLocation** ppEndLoc)
{
    if (func->funKind == FUNC_ROOT)
    {
        // Since all funclets are pulled out of line, the main code size is everything
        // up to the first handler. If the function is hot/cold split, we need to get the
        // appropriate sub-range.

        if (getHotSectionData)
        {
            *ppStartLoc = nullptr; // nullptr emit location means the beginning of the code. This is to handle the first
                                   // fragment prolog.

            if (fgFirstColdBlock != nullptr)
            {
                // The hot section only goes up to the cold section
                assert(fgFirstFuncletBB == nullptr);

                *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock));
            }
            else
            {
                if (fgFirstFuncletBB != nullptr)
                {
                    *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstFuncletBB));
                }
                else
                {
                    *ppEndLoc = nullptr; // nullptr end location means the end of the code
                }
            }
        }
        else
        {
            assert(fgFirstFuncletBB == nullptr); // TODO-CQ: support hot/cold splitting in functions with EH
            assert(fgFirstColdBlock != nullptr); // There better be a cold section!

            *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock));
            *ppEndLoc   = nullptr; // nullptr end location means the end of the code
        }
    }
    else
    {
        assert(getHotSectionData); // TODO-CQ: support funclets in cold section

        EHblkDsc* HBtab = ehGetDsc(func->funEHIndex);

        if (func->funKind == FUNC_FILTER)
        {
            assert(HBtab->HasFilter());
            *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdFilter));
            *ppEndLoc   = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndBeg));
        }
        else
        {
            assert(func->funKind == FUNC_HANDLER);
            *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndBeg));
            *ppEndLoc   = (HBtab->ebdHndLast->bbNext == nullptr)
                            ? nullptr
                            : new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndLast->bbNext));
        }
    }
}

#endif // FEATURE_EH_FUNCLETS

#if defined(_TARGET_UNIX_)

void Compiler::createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR cfiOpcode, USHORT dwarfReg, INT offset)
{
    CFI_CODE cfiEntry(codeOffset, cfiOpcode, dwarfReg, offset);
    func->cfiCodes->push_back(cfiEntry);
}

void Compiler::unwindPushCFI(regNumber reg)
{
    assert(compGeneratingProlog);

    FuncInfoDsc* func = funCurrentFunc();

    unsigned int cbProlog = unwindGetCurrentOffset(func);
    noway_assert((BYTE)cbProlog == cbProlog);

    createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, REGSIZE_BYTES == 8 ? 8 : 4);
    if ((RBM_CALLEE_SAVED & genRegMask(reg))
#if defined(UNIX_AMD64_ABI)
#if ETW_EBP_FRAMED
        // In case of ETW_EBP_FRAMED defined the REG_FPBASE (RBP)
        // is excluded from the callee-save register list.
        // Make sure the register gets PUSH unwind info in this case,
        // since it is pushed as a frame register.
        || (reg == REG_FPBASE)
#endif // ETW_EBP_FRAMED
#endif
            )
    {
        createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg));
    }
}

template <typename T>
inline static T* allocate_any(jitstd::allocator<void>& alloc, size_t count = 5)
{
    return jitstd::allocator<T>(alloc).allocate(count);
}

typedef jitstd::vector<CFI_CODE> CFICodeVector;

void Compiler::unwindBegPrologCFI()
{
    assert(compGeneratingProlog);

#if FEATURE_EH_FUNCLETS
    FuncInfoDsc* func = funCurrentFunc();

    // There is only one prolog for a function/funclet, and it comes first. So now is
    // a good time to initialize all the unwind data structures.

    unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);

    if (fgFirstColdBlock != nullptr)
    {
        unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
    }

    jitstd::allocator<void> allocator(getAllocator());

    func->cfiCodes = new (allocate_any<CFICodeVector>(allocator), jitstd::placement_t()) CFICodeVector(allocator);
#endif // FEATURE_EH_FUNCLETS
}

void Compiler::unwindPushMaskCFI(regMaskTP regMask, bool isFloat)
{
    regMaskTP regBit = isFloat ? genRegMask(REG_FP_FIRST) : 1;

    for (regNumber regNum = isFloat ? REG_FP_FIRST : REG_FIRST; regNum < REG_COUNT;
         regNum           = REG_NEXT(regNum), regBit <<= 1)
    {
        if (regBit > regMask)
        {
            break;
        }

        if (regBit & regMask)
        {
            unwindPushCFI(regNum);
        }
    }
}

void Compiler::unwindAllocStackCFI(unsigned size)
{
    assert(compGeneratingProlog);

    FuncInfoDsc* func = funCurrentFunc();

    unsigned int cbProlog = unwindGetCurrentOffset(func);
    noway_assert((BYTE)cbProlog == cbProlog);
    createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, size);
}

//------------------------------------------------------------------------
// Compiler::unwindSetFrameRegCFI: Record a cfi info for a frame register set.
//
// Arguments:
//    reg    - The register being set as the frame register.
//    offset - The offset from the current stack pointer that the frame pointer will point at.
//
void Compiler::unwindSetFrameRegCFI(regNumber reg, unsigned offset)
{
    assert(compGeneratingProlog);
    FuncInfoDsc* func = funCurrentFunc();

    unsigned int cbProlog = unwindGetCurrentOffset(func);
    noway_assert((BYTE)cbProlog == cbProlog);

    createCfiCode(func, cbProlog, CFI_DEF_CFA_REGISTER, mapRegNumToDwarfReg(reg));
    if (offset != 0)
    {
        // before: cfa = rsp + old_cfa_offset;
        //         rbp = rsp + offset;
        // after: cfa should be based on rbp, but points to the old address:
        //         rsp + old_cfa_offset == rbp + old_cfa_offset + adjust;
        // adjust = -offset;
        int adjust = -(int)offset;
        createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, adjust);
    }
}

void Compiler::unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdCode)
{
    UNATIVE_OFFSET startOffset;
    UNATIVE_OFFSET endOffset;
    DWORD          unwindCodeBytes = 0;
    BYTE*          pUnwindBlock    = nullptr;

    if (func->startLoc == nullptr)
    {
        startOffset = 0;
    }
    else
    {
        startOffset = func->startLoc->CodeOffset(genEmitter);
    }

    if (func->endLoc == nullptr)
    {
        endOffset = info.compNativeCodeSize;
    }
    else
    {
        endOffset = func->endLoc->CodeOffset(genEmitter);
    }

    DWORD size = (DWORD)func->cfiCodes->size();
    if (size > 0)
    {
        unwindCodeBytes = size * sizeof(CFI_CODE);
        pUnwindBlock    = (BYTE*)&(*func->cfiCodes)[0];
    }

#ifdef DEBUG
    if (opts.dspUnwind)
    {
        DumpCfiInfo(true /*isHotCode*/, startOffset, endOffset, unwindCodeBytes, (const CFI_CODE* const)pUnwindBlock);
    }
#endif // DEBUG

    assert(endOffset <= info.compTotalHotCodeSize);

    eeAllocUnwindInfo((BYTE*)pHotCode, nullptr /* pColdCode */, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
                      (CorJitFuncKind)func->funKind);

    if (pColdCode != nullptr)
    {
        assert(fgFirstColdBlock != nullptr);
        assert(func->funKind == FUNC_ROOT); // No splitting of funclets.

        unwindCodeBytes = 0;
        pUnwindBlock    = nullptr;

        if (func->coldStartLoc == nullptr)
        {
            startOffset = 0;
        }
        else
        {
            startOffset = func->coldStartLoc->CodeOffset(genEmitter);
        }

        if (func->coldEndLoc == nullptr)
        {
            endOffset = info.compNativeCodeSize;
        }
        else
        {
            endOffset = func->coldEndLoc->CodeOffset(genEmitter);
        }

#ifdef DEBUG
        if (opts.dspUnwind)
        {
            DumpCfiInfo(false /*isHotCode*/, startOffset, endOffset, unwindCodeBytes,
                        (const CFI_CODE* const)pUnwindBlock);
        }
#endif // DEBUG

        assert(startOffset >= info.compTotalHotCodeSize);
        startOffset -= info.compTotalHotCodeSize;
        endOffset -= info.compTotalHotCodeSize;

        eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
                          (CorJitFuncKind)func->funKind);
    }
}

#ifdef DEBUG
//------------------------------------------------------------------------
// DumpCfiInfo: Dump the Cfi data.
//
// Arguments:
//    isHotCode   - true if this cfi data is for the hot section, false otherwise.
//    startOffset - byte offset of the code start that this cfi data represents.
//    endOffset   - byte offset of the code end   that this cfi data represents.
//    pcFiCode    - pointer to the cfi data blob.
//
void Compiler::DumpCfiInfo(bool                  isHotCode,
                           UNATIVE_OFFSET        startOffset,
                           UNATIVE_OFFSET        endOffset,
                           DWORD                 cfiCodeBytes,
                           const CFI_CODE* const pCfiCode)
{
    printf("Cfi Info%s:\n", isHotCode ? "" : " COLD");
    printf("  >> Start offset   : 0x%06x \n", dspOffset(startOffset));
    printf("  >>   End offset   : 0x%06x \n", dspOffset(endOffset));

    for (int i = 0; i < (int)(cfiCodeBytes / sizeof(CFI_CODE)); i++)
    {
        const CFI_CODE* const pCode = &(pCfiCode[i]);

        UCHAR codeOffset = pCode->CodeOffset;
        SHORT dwarfReg   = pCode->DwarfReg;
        INT   offset     = pCode->Offset;

        switch (pCode->CfiOpCode)
        {
            case CFI_REL_OFFSET:
                printf("    CodeOffset: 0x%02X Op: RelOffset DwarfReg:0x%x Offset:0x%X\n", codeOffset, dwarfReg,
                       offset);
                break;
            case CFI_DEF_CFA_REGISTER:
                assert(offset == 0);
                printf("    CodeOffset: 0x%02X Op: DefCfaRegister DwarfReg:0x%X\n", codeOffset, dwarfReg);
                break;
            case CFI_ADJUST_CFA_OFFSET:
                assert(dwarfReg == DWARF_REG_ILLEGAL);
                printf("    CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset);
                break;
            default:
                printf("    Unrecognized CFI_CODE: 0x%IX\n", *(UINT64*)pCode);
                break;
        }
    }
}
#endif // DEBUG

#endif // _TARGET_UNIX_

//------------------------------------------------------------------------
// Compiler::unwindGetCurrentOffset: Calculate the current byte offset of the
// prolog being generated.
//
// Arguments:
//    func - The main function or funclet of interest.
//
// Return Value:
//    The byte offset of the prolog currently being generated.
//
UNATIVE_OFFSET Compiler::unwindGetCurrentOffset(FuncInfoDsc* func)
{
    assert(compGeneratingProlog);
    UNATIVE_OFFSET offset;
    if (func->funKind == FUNC_ROOT)
    {
        offset = genEmitter->emitGetPrologOffsetEstimate();
    }
    else
    {
#if defined(_TARGET_AMD64_)
        assert(func->startLoc != nullptr);
        offset = func->startLoc->GetFuncletPrologOffset(genEmitter);
#else
        offset = 0; // TODO ???
#endif
    }

    return offset;
}

#if defined(_TARGET_AMD64_)

// See unwindAmd64.cpp

#elif defined(_TARGET_ARM64_)

// See unwindArm64.cpp

#elif defined(_TARGET_ARM_)

// See unwindArm.cpp

#elif defined(_TARGET_X86_)

// See unwindX86.cpp

#else // _TARGET_*

#error Unsupported or unset target architecture

#endif // _TARGET_*
<|endoftext|>


<commit_before>/*
    Empath - Mailer for KDE

    Copyright (C) 1998, 1999 Rik Hemsley rik@kde.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifdef __GNUG__
# pragma implementation "EmpathIndex.h"
#endif

// Qt includes
#include <qdatastream.h>
#include <qregexp.h>
#include <qfileinfo.h>
#include <qdir.h>

// KDE includes
#include <kglobal.h>
#include <kstddirs.h>

// Local includes
#include "EmpathIndexRecord.h"
#include "EmpathIndex.h"
#include "EmpathFolder.h"
#include "Empath.h"

// Implementation note:
//
// The value part is composed of an 8-bit byte, used for marking status,
// plus a serialised version of an EmpathIndexRecord. This saves us
// [de]serialising records when we only want to access the status.

EmpathIndex::EmpathIndex()
    :   blockSize_(1024),
        count_(0),
        unreadCount_(0),
        initialised_(false),
        dbf_(0)
{
    // Empty.
    empathDebug("");
}

EmpathIndex::EmpathIndex(const EmpathURL & folder)
	:	blockSize_(1024),
        folder_(folder),
        count_(0),
        unreadCount_(0),
        initialised_(false),
        dbf_(0)
{
    empathDebug(folder.asString());
    QString resDir =
        KGlobal::dirs()->saveLocation("indices", folder.mailboxName(), true);

    QDir d(resDir);

    if (!d.exists()) {
        if (!d.mkdir(resDir)) {
            empathDebug("Cannot make index dir " + resDir);
            return;
        }
    }

    QString legalName = folder.folderPath().replace(QRegExp("/"), "_");

    filename_ = resDir + "/" + legalName;

    QFileInfo fi(filename_);

    if (!fi.exists())
        initialised_ = false;

    _open();
}

EmpathIndex::~EmpathIndex()
{
    _close();
}

    void
EmpathIndex::setFilename(const QString & filename)
{
    filename_ = filename;
    _close();
    _open();
}

    void
EmpathIndex::setFolder(const EmpathURL & folder)
{
    folder_ = folder;
}

    EmpathIndexRecord *
EmpathIndex::record(const QCString & key)
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return 0;
    }

    datum k;
    k.dptr  = key.data();
    k.dsize = key.length();

    datum out = gdbm_fetch(dbf_, k);

    if (!out.dptr) {
        return 0;
    }

    QByteArray a;
    a.setRawData(out.dptr + 1, out.dsize - 1);

    EmpathIndexRecord * rec = new EmpathIndexRecord;

    QDataStream s(a, IO_ReadOnly);
    s >> *rec;

    a.resetRawData(out.dptr + 1, out.dsize - 1);

    rec->setStatus((RMM::MessageStatus)(out.dptr[0]));

    return rec;
}

    Q_UINT32
EmpathIndex::countUnread()
{
    return unreadCount_;
}

     Q_UINT32
EmpathIndex::count()
{
    return count_;
}

    void
EmpathIndex::sync()
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return;
    }

    EmpathFolder * f = empath->folder(folder_);

    if (!f) {
        empathDebug("Can't access my folder :(");
        return;
    }

    f->update();
}

    void
EmpathIndex::_close()
{
    if (dbf_ == 0) {
        empathDebug("dbf is not open");
        return;
    }

    gdbm_close(dbf_);

    count_ = unreadCount_ = 0;
}

    bool
EmpathIndex::_open()
{
    if (dbf_ != 0) {
        empathDebug("Already open");
        return true;
    }

    dbf_ = gdbm_open(
        filename_.local8Bit().data(), blockSize_, GDBM_WRCREAT, 0600, NULL);

    if (dbf_ == 0) {
        empathDebug(gdbm_strerror(gdbm_errno));
        return false;
    }

    count_ = unreadCount_ = 0;

    return true;
}

    QStrList
EmpathIndex::allKeys()
{
    QStrList l;

    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return l;
    }

    datum key = gdbm_firstkey(dbf_);

    while (key.dptr) {

        QCString s(key.dptr, key.dsize + 1);

        l.append(s);

        key = gdbm_nextkey(dbf_, key);
    }

    return l;
}

    bool
EmpathIndex::insert(const QCString & key, EmpathIndexRecord & rec)
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return false;
    }

    datum k;
    k.dptr  = key.data();
    k.dsize = key.length();

    QByteArray a;
    QDataStream s(a, IO_WriteOnly);
    s << rec;

    unsigned int dataSize = 1 + a.size();
    char * data = new char[dataSize];
    memcpy(data + 1, a.data(), a.size());
    data[0] = (unsigned char)(rec.status());

    datum d;
    d.dptr  = data;
    d.dsize = dataSize;

    int retval = gdbm_store(dbf_, k, d, GDBM_REPLACE);

    if (retval == -1) {
        empathDebug("Could not insert record !");
        return false;
    }

    ++count_;

    if (!(rec.status() & RMM::Read))
        ++unreadCount_;

    return true;
}

    bool
EmpathIndex::remove(const QCString & key)
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return false;
    }

    datum k;

    k.dptr  = const_cast<char *>(key.data());
    k.dsize = key.length();

    datum die = gdbm_fetch(dbf_, k);

    if (!die.dptr) {
        empathDebug("Record does not exist");
        return false;
    }

    RMM::MessageStatus status = (RMM::MessageStatus)(die.dptr[0]);

    bool ok = (gdbm_delete(dbf_, k) == 0);

    if (ok) {
        --count_;
        if (!(status & RMM::Read))
            --unreadCount_;

    } else {
        empathDebug("Could not delete record");
    }

    return ok;
}

    void
EmpathIndex::clear()
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return;
    }

    datum key = gdbm_firstkey(dbf_);

    while (key.dptr) {

        gdbm_delete(dbf_, key);
        key = gdbm_nextkey(dbf_, key);
    }

    count_ = unreadCount_ = 0;
}

    void
EmpathIndex::setStatus(const QString & id, RMM::MessageStatus status)
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return;
    }

    datum k;
    k.dptr  = const_cast<char *>(id.data());
    k.dsize = id.length();

    datum changer = gdbm_fetch(dbf_, k);

    if (!changer.dptr) {
        empathDebug("does not exist");
        return;
    }

    bool wasRead = ((RMM::MessageStatus)(changer.dptr[0])) & RMM::Read;
    bool isRead = status & RMM::Read;

    changer.dptr[0] = (unsigned char)(status);

    int retval = gdbm_store(dbf_, k, changer, GDBM_REPLACE);

    if (retval == -1) {
        empathDebug("Couldn't replace record");
        return;
    }

    if (wasRead && !isRead)
        unreadCount_++;

    if (!wasRead && isRead)
        unreadCount_--;
}

    QDateTime
EmpathIndex::lastModified() const
{
    QFileInfo fi(filename_);
    return fi.lastModified();
}

// vim:ts=4:sw=4:tw=78
<commit_msg>gcc gave a warning about the initialization order. This helps.<commit_after>/*
    Empath - Mailer for KDE

    Copyright (C) 1998, 1999 Rik Hemsley rik@kde.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifdef __GNUG__
# pragma implementation "EmpathIndex.h"
#endif

// Qt includes
#include <qdatastream.h>
#include <qregexp.h>
#include <qfileinfo.h>
#include <qdir.h>

// KDE includes
#include <kglobal.h>
#include <kstddirs.h>

// Local includes
#include "EmpathIndexRecord.h"
#include "EmpathIndex.h"
#include "EmpathFolder.h"
#include "Empath.h"

// Implementation note:
//
// The value part is composed of an 8-bit byte, used for marking status,
// plus a serialised version of an EmpathIndexRecord. This saves us
// [de]serialising records when we only want to access the status.

EmpathIndex::EmpathIndex()
    :   blockSize_(1024),
        dbf_(0),
        count_(0),
        unreadCount_(0),
        initialised_(false)
{
    // Empty.
    empathDebug("");
}

EmpathIndex::EmpathIndex(const EmpathURL & folder)
	:	blockSize_(1024),
        folder_(folder),
        dbf_(0),
        count_(0),
        unreadCount_(0),
        initialised_(false)
{
    empathDebug(folder.asString());
    QString resDir =
        KGlobal::dirs()->saveLocation("indices", folder.mailboxName(), true);

    QDir d(resDir);

    if (!d.exists()) {
        if (!d.mkdir(resDir)) {
            empathDebug("Cannot make index dir " + resDir);
            return;
        }
    }

    QString legalName = folder.folderPath().replace(QRegExp("/"), "_");

    // filename_ = resDir + "/" + legalName;
    filename_ = "/tmp/" + legalName;

    QFileInfo fi(filename_);

    if (!fi.exists())
        initialised_ = false;

    _open();
}

EmpathIndex::~EmpathIndex()
{
    _close();
}

    void
EmpathIndex::setFilename(const QString & filename)
{
    filename_ = filename;
    _close();
    _open();
}

    void
EmpathIndex::setFolder(const EmpathURL & folder)
{
    folder_ = folder;
}

    EmpathIndexRecord *
EmpathIndex::record(const QCString & key)
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return 0;
    }

    datum k;
    k.dptr  = key.data();
    k.dsize = key.length();

    datum out = gdbm_fetch(dbf_, k);

    if (!out.dptr) {
        return 0;
    }

    QByteArray a;
    a.setRawData(out.dptr + 1, out.dsize - 1);

    EmpathIndexRecord * rec = new EmpathIndexRecord;

    QDataStream s(a, IO_ReadOnly);
    s >> *rec;

    a.resetRawData(out.dptr + 1, out.dsize - 1);

    rec->setStatus((RMM::MessageStatus)(out.dptr[0]));

    return rec;
}

    Q_UINT32
EmpathIndex::countUnread()
{
    return unreadCount_;
}

     Q_UINT32
EmpathIndex::count()
{
    return count_;
}

    void
EmpathIndex::sync()
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return;
    }

    EmpathFolder * f = empath->folder(folder_);

    if (!f) {
        empathDebug("Can't access my folder :(");
        return;
    }

    f->update();
}

    void
EmpathIndex::_close()
{
    if (dbf_ == 0) {
        empathDebug("dbf is not open");
        return;
    }

    gdbm_close(dbf_);

    count_ = unreadCount_ = 0;
}

    bool
EmpathIndex::_open()
{
    if (dbf_ != 0) {
        empathDebug("Already open");
        return true;
    }

    dbf_ = gdbm_open(
        filename_.local8Bit().data(), blockSize_, GDBM_WRCREAT, 0600, NULL);

    if (dbf_ == 0) {
        empathDebug(gdbm_strerror(gdbm_errno));
        return false;
    }

    count_ = unreadCount_ = 0;

    return true;
}

    QStrList
EmpathIndex::allKeys()
{
    QStrList l;

    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return l;
    }

    datum key = gdbm_firstkey(dbf_);

    while (key.dptr) {

        QCString s(key.dptr, key.dsize + 1);

        l.append(s);

        key = gdbm_nextkey(dbf_, key);
    }

    return l;
}

    bool
EmpathIndex::insert(const QCString & key, EmpathIndexRecord & rec)
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return false;
    }

    datum k;
    k.dptr  = key.data();
    k.dsize = key.length();

    QByteArray a;
    QDataStream s(a, IO_WriteOnly);
    s << rec;

    unsigned int dataSize = 1 + a.size();
    char * data = new char[dataSize];
    memcpy(data + 1, a.data(), a.size());
    data[0] = (unsigned char)(rec.status());

    datum d;
    d.dptr  = data;
    d.dsize = dataSize;

    int retval = gdbm_store(dbf_, k, d, GDBM_REPLACE);

    if (retval == -1) {
        empathDebug("Could not insert record !");
        return false;
    }

    ++count_;

    if (!(rec.status() & RMM::Read))
        ++unreadCount_;

    return true;
}

    bool
EmpathIndex::remove(const QCString & key)
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return false;
    }

    datum k;

    k.dptr  = const_cast<char *>(key.data());
    k.dsize = key.length();

    datum die = gdbm_fetch(dbf_, k);

    if (!die.dptr) {
        empathDebug("Record does not exist");
        return false;
    }

    RMM::MessageStatus status = (RMM::MessageStatus)(die.dptr[0]);

    bool ok = (gdbm_delete(dbf_, k) == 0);

    if (ok) {
        --count_;
        if (!(status & RMM::Read))
            --unreadCount_;

    } else {
        empathDebug("Could not delete record");
    }

    return ok;
}

    void
EmpathIndex::clear()
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return;
    }

    datum key = gdbm_firstkey(dbf_);

    while (key.dptr) {

        gdbm_delete(dbf_, key);
        key = gdbm_nextkey(dbf_, key);
    }

    count_ = unreadCount_ = 0;
}

    void
EmpathIndex::setStatus(const QString & id, RMM::MessageStatus status)
{
    if ((dbf_ == 0) && !_open()) {
        empathDebug("Index not open!");
        return;
    }

    datum k;
    k.dptr  = const_cast<char *>(id.data());
    k.dsize = id.length();

    datum changer = gdbm_fetch(dbf_, k);

    if (!changer.dptr) {
        empathDebug("does not exist");
        return;
    }

    bool wasRead = ((RMM::MessageStatus)(changer.dptr[0])) & RMM::Read;
    bool isRead = status & RMM::Read;

    changer.dptr[0] = (unsigned char)(status);

    int retval = gdbm_store(dbf_, k, changer, GDBM_REPLACE);

    if (retval == -1) {
        empathDebug("Couldn't replace record");
        return;
    }

    if (wasRead && !isRead)
        unreadCount_++;

    if (!wasRead && isRead)
        unreadCount_--;
}

    QDateTime
EmpathIndex::lastModified() const
{
    QFileInfo fi(filename_);
    return fi.lastModified();
}

// vim:ts=4:sw=4:tw=78
<|endoftext|>


<commit_before>/*
  This file is part of KOrganizer.

  Copyright (c) 2001, 2002, 2003 Cornelius Schumacher <schumacher@kde.org>
  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeventeditor.h"
#include "koprefs.h"
#include "koeditorgeneralevent.h"
#include "koeditoralarms.h"
#include "koeditorrecurrence.h"
#include "koeditordetails.h"
#include "koeditorfreebusy.h"
#include "kogroupware.h"
#include "kohelper.h"
#include "kodialogmanager.h"
#include "incidencechanger.h"

#include <kcal/calendarresources.h>
#include <kcal/resourcecalendar.h>
#include <kcal/incidenceformatter.h>
#include <kcal/calendarlocal.h>

#include <kiconloader.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>

#include <QFrame>
#include <QPixmap>
#include <QPointer>
#include <QLayout>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QBoxLayout>

KOEventEditor::KOEventEditor( Calendar *calendar, QWidget *parent )
  : KOIncidenceEditor( QString(), calendar, parent ),
    mEvent( 0 ), mCalendar( 0 ), mGeneral( 0 ), mRecurrence( 0 ), mFreeBusy( 0 )
{
}

KOEventEditor::~KOEventEditor()
{
  if ( !mIsCounter ) {
    emit dialogClose( mEvent );
  }
}

bool KOEventEditor::incidenceModified() {
  Event *newEvent = 0;

  if ( mEvent ) {
    newEvent = mEvent->clone();
    fillEvent( newEvent );
  }
  return mEvent && !( *newEvent == *mEvent );
}

void KOEventEditor::init()
{
  setupGeneral();
  setupRecurrence();
  setupFreeBusy();
  setupDesignerTabs( "event" );

  // Propagate date time settings to recurrence tab
  connect( mGeneral, SIGNAL(dateTimesChanged(const QDateTime&,const QDateTime& )),
           mRecurrence, SLOT(setDateTimes(const QDateTime&,const QDateTime&)) );
  connect( mGeneral, SIGNAL(dateTimeStrChanged(const QString&)),
           mRecurrence, SLOT(setDateTimeStr(const QString&)) );
  connect( mFreeBusy, SIGNAL(dateTimesChanged(const QDateTime&,const QDateTime&)),
           mRecurrence, SLOT(setDateTimes(const QDateTime&,const QDateTime&)) );

  // Propagate date time settings to gantt tab and back
  connect( mGeneral, SIGNAL(dateTimesChanged(const QDateTime&,const QDateTime&)),
           mFreeBusy, SLOT(slotUpdateGanttView(const QDateTime&,const QDateTime&)) );
  connect( mFreeBusy, SIGNAL(dateTimesChanged(const QDateTime&,const QDateTime&)),
           mGeneral, SLOT(setDateTimes(const QDateTime&,const QDateTime&)) );

  connect( mGeneral, SIGNAL(focusReceivedSignal()),
           SIGNAL(focusReceivedSignal()) );

  connect( mGeneral, SIGNAL(openCategoryDialog()),
           SIGNAL(editCategories()) );
  connect( this, SIGNAL(updateCategoryConfig()),
           mGeneral, SIGNAL(updateCategoryConfig()) );

  connect( mFreeBusy, SIGNAL(updateAttendeeSummary(int)),
           mGeneral, SLOT(updateAttendeeSummary(int)) );

  connect( mGeneral, SIGNAL(editRecurrence()),
           mRecurrenceDialog, SLOT(show()) );
  connect( mRecurrenceDialog, SIGNAL(okClicked()),
           SLOT(updateRecurrenceSummary()) );

  connect( mGeneral, SIGNAL(acceptInvitation()),
           mFreeBusy, SLOT(acceptForMe()) );
  connect( mGeneral, SIGNAL(declineInvitation()),
           mFreeBusy, SLOT(declineForMe()) );

  updateRecurrenceSummary();
}

void KOEventEditor::reload()
{
  if ( mEvent ) {
    readEvent( mEvent, true );
  }
}

void KOEventEditor::setupGeneral()
{
  mGeneral = new KOEditorGeneralEvent( mCalendar, this );

  if( KOPrefs::instance()->mCompactDialogs ) {
    QFrame *topFrame = new QFrame();
    addPage( topFrame, i18nc( "@title:tab general event settings", "General" ) );
    topFrame->setWhatsThis( i18nc( "@info:whatsthis",
                                   "The General tab allows you to set the most "
                                   "common options for the event." ) );

    QBoxLayout *topLayout = new QVBoxLayout( topFrame );
    topLayout->setSpacing( spacingHint() );

    mGeneral->initHeader( topFrame, topLayout );
    mGeneral->initTime( topFrame, topLayout );
    mGeneral->initAlarm( topFrame, topLayout );
    mGeneral->enableAlarm( false );

    topLayout->addStretch( 1 );

    QFrame *topFrame2 = new QFrame();
    addPage( topFrame2, i18nc( "@title:tab", "Details" ) );

    QBoxLayout *topLayout2 = new QVBoxLayout( topFrame2 );
    topLayout2->setSpacing( spacingHint() );

    mGeneral->initClass( topFrame2, topLayout2 );
    mGeneral->initSecrecy( topFrame2, topLayout2 );
    mGeneral->initDescription( topFrame2, topLayout2 );
  } else {
    QFrame *topFrame = new QFrame();
    addPage( topFrame, i18nc( "@title:tab general event settings", "&General" ) );
    topFrame->setWhatsThis( i18nc( "@info:whatsthis",
                                   "The General tab allows you to set the most "
                                   "common options for the event." ) );

    QBoxLayout *topLayout = new QVBoxLayout( topFrame );
    topLayout->setSpacing( spacingHint() );

    mGeneral->initInvitationBar( topFrame, topLayout );
    mGeneral->initHeader( topFrame, topLayout );
    mGeneral->initTime( topFrame, topLayout );
    mGeneral->initDescription( topFrame, topLayout );
    mGeneral->initAttachments( topFrame, topLayout );
    connect( mGeneral, SIGNAL(openURL(const KUrl&)),
             this, SLOT(openURL(const KUrl&)) );
    connect( this, SIGNAL(signalAddAttachments(const QStringList&,const QStringList&,bool)),
             mGeneral, SLOT(addAttachments(const QStringList&,const QStringList&,bool)) );
  }

  mGeneral->finishSetup();
}

void KOEventEditor::modified( int modification )
{
  Q_UNUSED( modification );

  // Play dumb, just reload the event. This dialog has become so complicated
  // that there is no point in trying to be smart here...
  reload();
}

void KOEventEditor::setupRecurrence()
{
#if 0
  QFrame *topFrame = new QFrame();
  addPage( topFrame, i18nc( "@title:tab", "Rec&urrence" ) );

  topFrame->setWhatsThis( i18nc( "@info:whatsthis",
                                 "The Recurrence tab allows you to set options "
                                 "on how often this event recurs." ) );

  QBoxLayout *topLayout = new QVBoxLayout( topFrame );

  mRecurrence = new KOEditorRecurrence( topFrame );
  topLayout->addWidget( mRecurrence );
#endif
  mRecurrenceDialog = new KOEditorRecurrenceDialog( this );
  mRecurrenceDialog->hide();
  mRecurrence = mRecurrenceDialog->editor();
}

void KOEventEditor::setupFreeBusy()
{
  QFrame *freeBusyPage = new QFrame();
  addPage( freeBusyPage, i18nc( "@title:tab", "&Attendees" ) );
  freeBusyPage->setWhatsThis( i18nc( "@info:whatsthis",
                                     "The Free/Busy tab allows you to see "
                                     "whether other attendees are free or busy "
                                     "during your event." ) );

  QBoxLayout *topLayout = new QVBoxLayout( freeBusyPage );

  mAttendeeEditor = mFreeBusy = new KOEditorFreeBusy( spacingHint(), freeBusyPage );
  topLayout->addWidget( mFreeBusy );
}

void KOEventEditor::editIncidence( Incidence *incidence, Calendar *calendar )
{
  Event*event = dynamic_cast<Event*>( incidence );
  if ( event ) {
    init();

    mEvent = event;
    mCalendar = calendar;
    readEvent( mEvent, false );
  }

  setCaption( i18nc( "@title:window",
                     "Edit Event : %1", KOHelper::resourceLabel( calendar, incidence ) ) );
}

void KOEventEditor::newEvent()
{
  init();
  mEvent = 0;
  loadDefaults();
  setCaption( i18nc( "@title:window", "New Event" ) );
}

void KOEventEditor::setDates( const QDateTime &from, const QDateTime &to, bool allDay )
{
  mGeneral->setDefaults( from, to, allDay );
  mRecurrence->setDefaults( from, to, allDay );
  if ( mFreeBusy ) {
    if ( allDay ) {
      mFreeBusy->setDateTimes( from, to.addDays( 1 ) );
    } else {
      mFreeBusy->setDateTimes( from, to );
    }
  }
}

void KOEventEditor::setTexts( const QString &summary, const QString &description,
                              bool richDescription )
{
  if ( description.isEmpty() && summary.contains( "\n" ) ) {
    mGeneral->setDescription( summary, richDescription );
    int pos = summary.indexOf( "\n" );
    mGeneral->setSummary( summary.left( pos ) );
  } else {
    mGeneral->setSummary( summary );
    mGeneral->setDescription( description, richDescription );
  }
}

void KOEventEditor::loadDefaults()
{
  QDateTime from( QDate::currentDate(), KOPrefs::instance()->mStartTime.time() );
  int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour() * 3600 ) +
                ( KOPrefs::instance()->mDefaultDuration.time().minute() * 60 );
  QDateTime to( from.addSecs( addSecs ) );

  setDates( from, to, false );
}

bool KOEventEditor::processInput()
{
  if ( !validateInput() || !mChanger ) {
    return false;
  }

  QPointer<KOEditorFreeBusy> freeBusy( mFreeBusy );

  if ( mEvent ) {
    bool rc = true;
    Event *oldEvent = mEvent->clone();
    Event *event = mEvent->clone();

    fillEvent( event );

    if ( *event == *mEvent ) {
      // Don't do anything
      if ( mIsCounter ) {
        KMessageBox::information(
          this,
          i18n( "You didn't change the event, "
                "thus no counter proposal has been sent to the organizer." ),
          i18n( "No changes" ) );
      }
    } else {
      //IncidenceChanger::assignIncidence( mEvent, event );
      fillEvent( mEvent );
      if ( mIsCounter ) {
        KOGroupware::instance()->sendCounterProposal( mCalendar, oldEvent, mEvent );
        // add dummy event at the position of the counter proposal
        Event *event = mEvent->clone();
        event->clearAttendees();
        event->setSummary( i18n( "My counter proposal for: %1", mEvent->summary() ) );
        mChanger->addIncidence( event );
      } else {
        mChanger->changeIncidence( oldEvent, mEvent );
      }
    }
    delete event;
    delete oldEvent;
    return rc;
  } else {
    mEvent = new Event;
    mEvent->setOrganizer( Person( KOPrefs::instance()->fullName(),
                          KOPrefs::instance()->email() ) );
    fillEvent( mEvent );
    if ( !mChanger->addIncidence( mEvent, this ) ) {
      delete mEvent;
      mEvent = 0;
      return false;
    }
  }
  // if "this" was deleted, freeBusy is 0 (being a guardedptr)
  if ( freeBusy ) {
    freeBusy->cancelReload();
  }

  return true;
}

void KOEventEditor::processCancel()
{
  if ( mFreeBusy ) {
    mFreeBusy->cancelReload();
  }
}

void KOEventEditor::deleteEvent()
{
  if ( mEvent ) {
    emit deleteIncidenceSignal( mEvent );
  }

  emit dialogClose( mEvent );
  reject();
}

void KOEventEditor::readEvent( Event *event, bool tmpl )
{
  if ( !event ) {
    return;
  }

  mGeneral->readEvent( event, tmpl );
  mRecurrence->readIncidence( event );
  if ( mFreeBusy ) {
    mFreeBusy->readIncidence( event );
    mFreeBusy->triggerReload();
  }

  createEmbeddedURLPages( event );
  readDesignerFields( event );

  if ( mIsCounter ) {
    mGeneral->invitationBar()->hide();
  }
}

void KOEventEditor::fillEvent( Event *event )
{
  mGeneral->fillEvent( event );
  if ( mFreeBusy ) {
    mFreeBusy->fillIncidence( event );
  }

  cancelRemovedAttendees( event );

  mRecurrence->fillIncidence( event );

  writeDesignerFields( event );
}

bool KOEventEditor::validateInput()
{
  if ( !mGeneral->validateInput() ) {
    return false;
  }
  if ( !mDetails->validateInput() ) {
    return false;
  }
  if ( !mRecurrence->validateInput() ) {
    return false;
  }

  return true;
}

int KOEventEditor::msgItemDelete()
{
  return KMessageBox::warningContinueCancel(
    this,
    i18nc( "@info", "This item will be permanently deleted." ),
    i18nc( "@title:window", "KOrganizer Confirmation" ),
    KGuiItem( i18nc( "@action:button", "Delete" ), "edit-delete" ) );
}

void KOEventEditor::loadTemplate( CalendarLocal &cal )
{
  Event::List events = cal.events();
  if ( events.count() == 0 ) {
    KMessageBox::error( this, i18nc( "@info", "Template does not contain a valid event." ) );
  } else {
    readEvent( events.first(), true );
  }
}

QStringList &KOEventEditor::templates() const
{
  return KOPrefs::instance()->mEventTemplates;
}

void KOEventEditor::slotSaveTemplate( const QString &templateName )
{
  Event *event = new Event;
  fillEvent( event );
  saveAsTemplate( event, templateName );
}

QObject *KOEventEditor::typeAheadReceiver() const
{
  return mGeneral->typeAheadReceiver();
}

void KOEventEditor::updateRecurrenceSummary()
{
  Event *ev =  new Event();
  fillEvent( ev );
  mGeneral->updateRecurrenceSummary( IncidenceFormatter::recurrenceString( ev ) );
  delete ev;
}

void KOEventEditor::selectInvitationCounterProposal( bool enable )
{
  KOIncidenceEditor::selectInvitationCounterProposal( enable );
  if ( enable ) {
    mGeneral->invitationBar()->hide();
  }
}

#include "koeventeditor.moc"
<commit_msg>"Do you really want to cancel" was only working when editing events, not when creating a new one then canceling.<commit_after>/*
  This file is part of KOrganizer.

  Copyright (c) 2001, 2002, 2003 Cornelius Schumacher <schumacher@kde.org>
  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeventeditor.h"
#include "koprefs.h"
#include "koeditorgeneralevent.h"
#include "koeditoralarms.h"
#include "koeditorrecurrence.h"
#include "koeditordetails.h"
#include "koeditorfreebusy.h"
#include "kogroupware.h"
#include "kohelper.h"
#include "kodialogmanager.h"
#include "incidencechanger.h"

#include <kcal/calendarresources.h>
#include <kcal/resourcecalendar.h>
#include <kcal/incidenceformatter.h>
#include <kcal/calendarlocal.h>

#include <kiconloader.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>

#include <QFrame>
#include <QPixmap>
#include <QPointer>
#include <QLayout>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QBoxLayout>

KOEventEditor::KOEventEditor( Calendar *calendar, QWidget *parent )
  : KOIncidenceEditor( QString(), calendar, parent ),
    mEvent( 0 ), mCalendar( 0 ), mGeneral( 0 ), mRecurrence( 0 ), mFreeBusy( 0 )
{
}

KOEventEditor::~KOEventEditor()
{
  if ( !mIsCounter ) {
    emit dialogClose( mEvent );
  }
}

bool KOEventEditor::incidenceModified() {
  Event *newEvent = 0;

  if ( mEvent ) {
    newEvent = mEvent->clone();
    fillEvent( newEvent );
  }

  // If mEvent is 0 then it's a newly created event, lets count that as a modification
  // else, compare it with what the user entered in the editor

  return !mEvent || !( *newEvent == *mEvent );
}

void KOEventEditor::init()
{
  setupGeneral();
  setupRecurrence();
  setupFreeBusy();
  setupDesignerTabs( "event" );

  // Propagate date time settings to recurrence tab
  connect( mGeneral, SIGNAL(dateTimesChanged(const QDateTime&,const QDateTime& )),
           mRecurrence, SLOT(setDateTimes(const QDateTime&,const QDateTime&)) );
  connect( mGeneral, SIGNAL(dateTimeStrChanged(const QString&)),
           mRecurrence, SLOT(setDateTimeStr(const QString&)) );
  connect( mFreeBusy, SIGNAL(dateTimesChanged(const QDateTime&,const QDateTime&)),
           mRecurrence, SLOT(setDateTimes(const QDateTime&,const QDateTime&)) );

  // Propagate date time settings to gantt tab and back
  connect( mGeneral, SIGNAL(dateTimesChanged(const QDateTime&,const QDateTime&)),
           mFreeBusy, SLOT(slotUpdateGanttView(const QDateTime&,const QDateTime&)) );
  connect( mFreeBusy, SIGNAL(dateTimesChanged(const QDateTime&,const QDateTime&)),
           mGeneral, SLOT(setDateTimes(const QDateTime&,const QDateTime&)) );

  connect( mGeneral, SIGNAL(focusReceivedSignal()),
           SIGNAL(focusReceivedSignal()) );

  connect( mGeneral, SIGNAL(openCategoryDialog()),
           SIGNAL(editCategories()) );
  connect( this, SIGNAL(updateCategoryConfig()),
           mGeneral, SIGNAL(updateCategoryConfig()) );

  connect( mFreeBusy, SIGNAL(updateAttendeeSummary(int)),
           mGeneral, SLOT(updateAttendeeSummary(int)) );

  connect( mGeneral, SIGNAL(editRecurrence()),
           mRecurrenceDialog, SLOT(show()) );
  connect( mRecurrenceDialog, SIGNAL(okClicked()),
           SLOT(updateRecurrenceSummary()) );

  connect( mGeneral, SIGNAL(acceptInvitation()),
           mFreeBusy, SLOT(acceptForMe()) );
  connect( mGeneral, SIGNAL(declineInvitation()),
           mFreeBusy, SLOT(declineForMe()) );

  updateRecurrenceSummary();
}

void KOEventEditor::reload()
{
  if ( mEvent ) {
    readEvent( mEvent, true );
  }
}

void KOEventEditor::setupGeneral()
{
  mGeneral = new KOEditorGeneralEvent( mCalendar, this );

  if( KOPrefs::instance()->mCompactDialogs ) {
    QFrame *topFrame = new QFrame();
    addPage( topFrame, i18nc( "@title:tab general event settings", "General" ) );
    topFrame->setWhatsThis( i18nc( "@info:whatsthis",
                                   "The General tab allows you to set the most "
                                   "common options for the event." ) );

    QBoxLayout *topLayout = new QVBoxLayout( topFrame );
    topLayout->setSpacing( spacingHint() );

    mGeneral->initHeader( topFrame, topLayout );
    mGeneral->initTime( topFrame, topLayout );
    mGeneral->initAlarm( topFrame, topLayout );
    mGeneral->enableAlarm( false );

    topLayout->addStretch( 1 );

    QFrame *topFrame2 = new QFrame();
    addPage( topFrame2, i18nc( "@title:tab", "Details" ) );

    QBoxLayout *topLayout2 = new QVBoxLayout( topFrame2 );
    topLayout2->setSpacing( spacingHint() );

    mGeneral->initClass( topFrame2, topLayout2 );
    mGeneral->initSecrecy( topFrame2, topLayout2 );
    mGeneral->initDescription( topFrame2, topLayout2 );
  } else {
    QFrame *topFrame = new QFrame();
    addPage( topFrame, i18nc( "@title:tab general event settings", "&General" ) );
    topFrame->setWhatsThis( i18nc( "@info:whatsthis",
                                   "The General tab allows you to set the most "
                                   "common options for the event." ) );

    QBoxLayout *topLayout = new QVBoxLayout( topFrame );
    topLayout->setSpacing( spacingHint() );

    mGeneral->initInvitationBar( topFrame, topLayout );
    mGeneral->initHeader( topFrame, topLayout );
    mGeneral->initTime( topFrame, topLayout );
    mGeneral->initDescription( topFrame, topLayout );
    mGeneral->initAttachments( topFrame, topLayout );
    connect( mGeneral, SIGNAL(openURL(const KUrl&)),
             this, SLOT(openURL(const KUrl&)) );
    connect( this, SIGNAL(signalAddAttachments(const QStringList&,const QStringList&,bool)),
             mGeneral, SLOT(addAttachments(const QStringList&,const QStringList&,bool)) );
  }

  mGeneral->finishSetup();
}

void KOEventEditor::modified( int modification )
{
  Q_UNUSED( modification );

  // Play dumb, just reload the event. This dialog has become so complicated
  // that there is no point in trying to be smart here...
  reload();
}

void KOEventEditor::setupRecurrence()
{
#if 0
  QFrame *topFrame = new QFrame();
  addPage( topFrame, i18nc( "@title:tab", "Rec&urrence" ) );

  topFrame->setWhatsThis( i18nc( "@info:whatsthis",
                                 "The Recurrence tab allows you to set options "
                                 "on how often this event recurs." ) );

  QBoxLayout *topLayout = new QVBoxLayout( topFrame );

  mRecurrence = new KOEditorRecurrence( topFrame );
  topLayout->addWidget( mRecurrence );
#endif
  mRecurrenceDialog = new KOEditorRecurrenceDialog( this );
  mRecurrenceDialog->hide();
  mRecurrence = mRecurrenceDialog->editor();
}

void KOEventEditor::setupFreeBusy()
{
  QFrame *freeBusyPage = new QFrame();
  addPage( freeBusyPage, i18nc( "@title:tab", "&Attendees" ) );
  freeBusyPage->setWhatsThis( i18nc( "@info:whatsthis",
                                     "The Free/Busy tab allows you to see "
                                     "whether other attendees are free or busy "
                                     "during your event." ) );

  QBoxLayout *topLayout = new QVBoxLayout( freeBusyPage );

  mAttendeeEditor = mFreeBusy = new KOEditorFreeBusy( spacingHint(), freeBusyPage );
  topLayout->addWidget( mFreeBusy );
}

void KOEventEditor::editIncidence( Incidence *incidence, Calendar *calendar )
{
  Event*event = dynamic_cast<Event*>( incidence );
  if ( event ) {
    init();

    mEvent = event;
    mCalendar = calendar;
    readEvent( mEvent, false );
  }

  setCaption( i18nc( "@title:window",
                     "Edit Event : %1", KOHelper::resourceLabel( calendar, incidence ) ) );
}

void KOEventEditor::newEvent()
{
  init();
  mEvent = 0;
  loadDefaults();
  setCaption( i18nc( "@title:window", "New Event" ) );
}

void KOEventEditor::setDates( const QDateTime &from, const QDateTime &to, bool allDay )
{
  mGeneral->setDefaults( from, to, allDay );
  mRecurrence->setDefaults( from, to, allDay );
  if ( mFreeBusy ) {
    if ( allDay ) {
      mFreeBusy->setDateTimes( from, to.addDays( 1 ) );
    } else {
      mFreeBusy->setDateTimes( from, to );
    }
  }
}

void KOEventEditor::setTexts( const QString &summary, const QString &description,
                              bool richDescription )
{
  if ( description.isEmpty() && summary.contains( "\n" ) ) {
    mGeneral->setDescription( summary, richDescription );
    int pos = summary.indexOf( "\n" );
    mGeneral->setSummary( summary.left( pos ) );
  } else {
    mGeneral->setSummary( summary );
    mGeneral->setDescription( description, richDescription );
  }
}

void KOEventEditor::loadDefaults()
{
  QDateTime from( QDate::currentDate(), KOPrefs::instance()->mStartTime.time() );
  int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour() * 3600 ) +
                ( KOPrefs::instance()->mDefaultDuration.time().minute() * 60 );
  QDateTime to( from.addSecs( addSecs ) );

  setDates( from, to, false );
}

bool KOEventEditor::processInput()
{
  if ( !validateInput() || !mChanger ) {
    return false;
  }

  QPointer<KOEditorFreeBusy> freeBusy( mFreeBusy );

  if ( mEvent ) {
    bool rc = true;
    Event *oldEvent = mEvent->clone();
    Event *event = mEvent->clone();

    fillEvent( event );

    if ( *event == *mEvent ) {
      // Don't do anything
      if ( mIsCounter ) {
        KMessageBox::information(
          this,
          i18n( "You didn't change the event, "
                "thus no counter proposal has been sent to the organizer." ),
          i18n( "No changes" ) );
      }
    } else {
      //IncidenceChanger::assignIncidence( mEvent, event );
      fillEvent( mEvent );
      if ( mIsCounter ) {
        KOGroupware::instance()->sendCounterProposal( mCalendar, oldEvent, mEvent );
        // add dummy event at the position of the counter proposal
        Event *event = mEvent->clone();
        event->clearAttendees();
        event->setSummary( i18n( "My counter proposal for: %1", mEvent->summary() ) );
        mChanger->addIncidence( event );
      } else {
        mChanger->changeIncidence( oldEvent, mEvent );
      }
    }
    delete event;
    delete oldEvent;
    return rc;
  } else {
    mEvent = new Event;
    mEvent->setOrganizer( Person( KOPrefs::instance()->fullName(),
                          KOPrefs::instance()->email() ) );
    fillEvent( mEvent );
    if ( !mChanger->addIncidence( mEvent, this ) ) {
      delete mEvent;
      mEvent = 0;
      return false;
    }
  }
  // if "this" was deleted, freeBusy is 0 (being a guardedptr)
  if ( freeBusy ) {
    freeBusy->cancelReload();
  }

  return true;
}

void KOEventEditor::processCancel()
{
  if ( mFreeBusy ) {
    mFreeBusy->cancelReload();
  }
}

void KOEventEditor::deleteEvent()
{
  if ( mEvent ) {
    emit deleteIncidenceSignal( mEvent );
  }

  emit dialogClose( mEvent );
  reject();
}

void KOEventEditor::readEvent( Event *event, bool tmpl )
{
  if ( !event ) {
    return;
  }

  mGeneral->readEvent( event, tmpl );
  mRecurrence->readIncidence( event );
  if ( mFreeBusy ) {
    mFreeBusy->readIncidence( event );
    mFreeBusy->triggerReload();
  }

  createEmbeddedURLPages( event );
  readDesignerFields( event );

  if ( mIsCounter ) {
    mGeneral->invitationBar()->hide();
  }
}

void KOEventEditor::fillEvent( Event *event )
{
  mGeneral->fillEvent( event );
  if ( mFreeBusy ) {
    mFreeBusy->fillIncidence( event );
  }

  cancelRemovedAttendees( event );

  mRecurrence->fillIncidence( event );

  writeDesignerFields( event );
}

bool KOEventEditor::validateInput()
{
  if ( !mGeneral->validateInput() ) {
    return false;
  }
  if ( !mDetails->validateInput() ) {
    return false;
  }
  if ( !mRecurrence->validateInput() ) {
    return false;
  }

  return true;
}

int KOEventEditor::msgItemDelete()
{
  return KMessageBox::warningContinueCancel(
    this,
    i18nc( "@info", "This item will be permanently deleted." ),
    i18nc( "@title:window", "KOrganizer Confirmation" ),
    KGuiItem( i18nc( "@action:button", "Delete" ), "edit-delete" ) );
}

void KOEventEditor::loadTemplate( CalendarLocal &cal )
{
  Event::List events = cal.events();
  if ( events.count() == 0 ) {
    KMessageBox::error( this, i18nc( "@info", "Template does not contain a valid event." ) );
  } else {
    readEvent( events.first(), true );
  }
}

QStringList &KOEventEditor::templates() const
{
  return KOPrefs::instance()->mEventTemplates;
}

void KOEventEditor::slotSaveTemplate( const QString &templateName )
{
  Event *event = new Event;
  fillEvent( event );
  saveAsTemplate( event, templateName );
}

QObject *KOEventEditor::typeAheadReceiver() const
{
  return mGeneral->typeAheadReceiver();
}

void KOEventEditor::updateRecurrenceSummary()
{
  Event *ev =  new Event();
  fillEvent( ev );
  mGeneral->updateRecurrenceSummary( IncidenceFormatter::recurrenceString( ev ) );
  delete ev;
}

void KOEventEditor::selectInvitationCounterProposal( bool enable )
{
  KOIncidenceEditor::selectInvitationCounterProposal( enable );
  if ( enable ) {
    mGeneral->invitationBar()->hide();
  }
}

#include "koeventeditor.moc"
<|endoftext|>