<commit_before>#include "store-api.hh"
#include "globals.hh"
#include "util.hh"

#include <limits.h>

namespace nix {

GCOptions::GCOptions()
{
    action = gcDeleteDead;
    ignoreLiveness = false;
    maxFreed = ULLONG_MAX;
    maxLinks = 0;
    useAtime = false;
    maxAtime = (time_t) -1;
}

bool isInStore(const Path & path)
{
    return path[0] == '/'
        && string(path, 0, nixStore.size()) == nixStore
        && path.size() >= nixStore.size() + 2
        && path[nixStore.size()] == '/';
}

bool isStorePath(const Path & path)
{
    return isInStore(path)
        && path.find('/', nixStore.size() + 1) == Path::npos;
}

void assertStorePath(const Path & path)
{
    if (!isStorePath(path))
        throw Error(format("path `%1%' is not in the Nix store") % path);
}

Path toStorePath(const Path & path)
{
    if (!isInStore(path))
        throw Error(format("path `%1%' is not in the Nix store") % path);
    Path::size_type slash = path.find('/', nixStore.size() + 1);
    if (slash == Path::npos)
        return path;
    else
        return Path(path, 0, slash);
}

Path followLinksToStore(const Path & _path)
{
    Path path = absPath(_path);
    while (!isInStore(path)) {
        if (!isLink(path)) break;
        string target = readLink(path);
        path = absPath(target, dirOf(path));
    }
    if (!isInStore(path))
        throw Error(format("path `%1%' is not in the Nix store") % path);
    return path;
}

Path followLinksToStorePath(const Path & path)
{
    return toStorePath(followLinksToStore(path));
}

void checkStoreName(const string & name)
{
    string validChars = "+-._?=";
    /* Disallow names starting with a dot for possible security
       reasons (e.g., "." and ".."). */
    if (string(name, 0, 1) == ".")
        throw Error(format("illegal name: `%1%'") % name);
    for (string::const_iterator i = name.begin(); i != name.end(); ++i)
        if (!((*i >= 'A' && *i <= 'Z') ||
              (*i >= 'a' && *i <= 'z') ||
              (*i >= '0' && *i <= '9') ||
              validChars.find(*i) != string::npos))
        {
            throw Error(format("invalid character `%1%' in name `%2%'")
                % *i % name);
        }
}

Path makeStorePath(const string & type,
    const Hash & hash, const string & suffix)
{
    /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
    string s = type + ":sha256:" + printHash(hash) + ":"
        + nixStore + ":" + suffix;

    checkStoreName(suffix);

    return nixStore + "/"
        + printHash32(compressHash(hashString(htSHA256, s), 20))
        + "-" + suffix;
}

Path makeFixedOutputPath(bool recursive,
    string hashAlgo, Hash hash, string name)
{
    /* !!! copy/paste from primops.cc */
    Hash h = hashString(htSHA256, "fixed:out:"
        + (recursive ? (string) "r:" : "") + hashAlgo + ":"
        + printHash(hash) + ":"
        + "");
    return makeStorePath("output:out", h, name);
}

std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
    bool fixed, bool recursive, string hashAlgo, PathFilter & filter)
{
    Hash h = hashPath(htSHA256, srcPath, filter);

    string baseName = baseNameOf(srcPath);

    Path dstPath;

    if (fixed) {
        HashType ht(parseHashType(hashAlgo));
        Hash h2 = recursive ? hashPath(ht, srcPath, filter) : hashFile(ht, srcPath);
        dstPath = makeFixedOutputPath(recursive, hashAlgo, h2, baseName);
    }

    else dstPath = makeStorePath("source", h, baseName);

    return std::pair<Path, Hash>(dstPath, h);
}

Path computeStorePathForText(const string & suffix, const string & s,
    const PathSet & references)
{
    Hash hash = hashString(htSHA256, s);
    /* Stuff the references (if any) into the type.  This is a bit
       hacky, but we can't put them in `s' since that would be
       ambiguous. */
    string type = "text";
    for (PathSet::const_iterator i = references.begin(); i != references.end(); ++i) {
        type += ":";
        type += *i;
    }
    return makeStorePath(type, hash, suffix);
}

/* Return a string accepted by decodeValidPathInfo() that
   registers the specified paths as valid.  Note: it's the
   responsibility of the caller to provide a closure. */
string makeValidityRegistration(const PathSet & paths,
    bool showDerivers, bool showHash)
{
    string s = "";

    for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
        s += *i + "\n";

        if (showHash)
            s += printHash(store->queryPathHash(*i)) + "\n";

        Path deriver = showDerivers ? store->queryDeriver(*i) : "";
        s += deriver + "\n";

        PathSet references;
        store->queryReferences(*i, references);

        s += (format("%1%\n") % references.size()).str();

        for (PathSet::iterator j = references.begin();
             j != references.end(); ++j)
            s += *j + "\n";
    }

    return s;
}

ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven)
{
    ValidPathInfo info;
    getline(str, info.path);
    if (str.eof()) { info.path = ""; return info; }
    if (hashGiven) {
        string s;
        getline(str, s);
        info.hash = parseHash(htSHA256, s);
    }
    getline(str, info.deriver);
    string s; int n;
    getline(str, s);
    if (!string2Int(s, n)) throw Error("number expected");
    while (n--) {
        getline(str, s);
        info.references.insert(s);
    }
    if (!str || str.eof()) throw Error("missing input");
    return info;
}

string showPaths(const PathSet & paths)
{
    string s;
    for (PathSet::const_iterator i = paths.begin();
         i != paths.end(); ++i)
    {
        if (s.size() != 0) s += ", ";
        s += "`" + *i + "'";
    }
    return s;
}

}

#include "local-store.hh"
#include "serialise.hh"
#include "remote-store.hh"

namespace nix {

boost::shared_ptr<StoreAPI> store;

boost::shared_ptr<StoreAPI> openStore()
{
    if (getEnv("NIX_REMOTE") == "")
        return boost::shared_ptr<StoreAPI>(new LocalStore());
    else
        return boost::shared_ptr<StoreAPI>(new RemoteStore());
}

}
<commit_msg>* Bug fix for building on some old installations (contributed by Pjotr).<commit_after>#include "store-api.hh"
#include "globals.hh"
#include "util.hh"

#include <limits.h>

/* Needed for some ancient environments. */
#ifndef ULLONG_MAX
#define ULLONG_MAX 18446744073709551615
#endif

namespace nix {

GCOptions::GCOptions()
{
    action = gcDeleteDead;
    ignoreLiveness = false;
    maxFreed = ULLONG_MAX;
    maxLinks = 0;
    useAtime = false;
    maxAtime = (time_t) -1;
}

bool isInStore(const Path & path)
{
    return path[0] == '/'
        && string(path, 0, nixStore.size()) == nixStore
        && path.size() >= nixStore.size() + 2
        && path[nixStore.size()] == '/';
}

bool isStorePath(const Path & path)
{
    return isInStore(path)
        && path.find('/', nixStore.size() + 1) == Path::npos;
}

void assertStorePath(const Path & path)
{
    if (!isStorePath(path))
        throw Error(format("path `%1%' is not in the Nix store") % path);
}

Path toStorePath(const Path & path)
{
    if (!isInStore(path))
        throw Error(format("path `%1%' is not in the Nix store") % path);
    Path::size_type slash = path.find('/', nixStore.size() + 1);
    if (slash == Path::npos)
        return path;
    else
        return Path(path, 0, slash);
}

Path followLinksToStore(const Path & _path)
{
    Path path = absPath(_path);
    while (!isInStore(path)) {
        if (!isLink(path)) break;
        string target = readLink(path);
        path = absPath(target, dirOf(path));
    }
    if (!isInStore(path))
        throw Error(format("path `%1%' is not in the Nix store") % path);
    return path;
}

Path followLinksToStorePath(const Path & path)
{
    return toStorePath(followLinksToStore(path));
}

void checkStoreName(const string & name)
{
    string validChars = "+-._?=";
    /* Disallow names starting with a dot for possible security
       reasons (e.g., "." and ".."). */
    if (string(name, 0, 1) == ".")
        throw Error(format("illegal name: `%1%'") % name);
    for (string::const_iterator i = name.begin(); i != name.end(); ++i)
        if (!((*i >= 'A' && *i <= 'Z') ||
              (*i >= 'a' && *i <= 'z') ||
              (*i >= '0' && *i <= '9') ||
              validChars.find(*i) != string::npos))
        {
            throw Error(format("invalid character `%1%' in name `%2%'")
                % *i % name);
        }
}

Path makeStorePath(const string & type,
    const Hash & hash, const string & suffix)
{
    /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
    string s = type + ":sha256:" + printHash(hash) + ":"
        + nixStore + ":" + suffix;

    checkStoreName(suffix);

    return nixStore + "/"
        + printHash32(compressHash(hashString(htSHA256, s), 20))
        + "-" + suffix;
}

Path makeFixedOutputPath(bool recursive,
    string hashAlgo, Hash hash, string name)
{
    /* !!! copy/paste from primops.cc */
    Hash h = hashString(htSHA256, "fixed:out:"
        + (recursive ? (string) "r:" : "") + hashAlgo + ":"
        + printHash(hash) + ":"
        + "");
    return makeStorePath("output:out", h, name);
}

std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
    bool fixed, bool recursive, string hashAlgo, PathFilter & filter)
{
    Hash h = hashPath(htSHA256, srcPath, filter);

    string baseName = baseNameOf(srcPath);

    Path dstPath;

    if (fixed) {
        HashType ht(parseHashType(hashAlgo));
        Hash h2 = recursive ? hashPath(ht, srcPath, filter) : hashFile(ht, srcPath);
        dstPath = makeFixedOutputPath(recursive, hashAlgo, h2, baseName);
    }

    else dstPath = makeStorePath("source", h, baseName);

    return std::pair<Path, Hash>(dstPath, h);
}

Path computeStorePathForText(const string & suffix, const string & s,
    const PathSet & references)
{
    Hash hash = hashString(htSHA256, s);
    /* Stuff the references (if any) into the type.  This is a bit
       hacky, but we can't put them in `s' since that would be
       ambiguous. */
    string type = "text";
    for (PathSet::const_iterator i = references.begin(); i != references.end(); ++i) {
        type += ":";
        type += *i;
    }
    return makeStorePath(type, hash, suffix);
}

/* Return a string accepted by decodeValidPathInfo() that
   registers the specified paths as valid.  Note: it's the
   responsibility of the caller to provide a closure. */
string makeValidityRegistration(const PathSet & paths,
    bool showDerivers, bool showHash)
{
    string s = "";

    for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
        s += *i + "\n";

        if (showHash)
            s += printHash(store->queryPathHash(*i)) + "\n";

        Path deriver = showDerivers ? store->queryDeriver(*i) : "";
        s += deriver + "\n";

        PathSet references;
        store->queryReferences(*i, references);

        s += (format("%1%\n") % references.size()).str();

        for (PathSet::iterator j = references.begin();
             j != references.end(); ++j)
            s += *j + "\n";
    }

    return s;
}

ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven)
{
    ValidPathInfo info;
    getline(str, info.path);
    if (str.eof()) { info.path = ""; return info; }
    if (hashGiven) {
        string s;
        getline(str, s);
        info.hash = parseHash(htSHA256, s);
    }
    getline(str, info.deriver);
    string s; int n;
    getline(str, s);
    if (!string2Int(s, n)) throw Error("number expected");
    while (n--) {
        getline(str, s);
        info.references.insert(s);
    }
    if (!str || str.eof()) throw Error("missing input");
    return info;
}

string showPaths(const PathSet & paths)
{
    string s;
    for (PathSet::const_iterator i = paths.begin();
         i != paths.end(); ++i)
    {
        if (s.size() != 0) s += ", ";
        s += "`" + *i + "'";
    }
    return s;
}

}

#include "local-store.hh"
#include "serialise.hh"
#include "remote-store.hh"

namespace nix {

boost::shared_ptr<StoreAPI> store;

boost::shared_ptr<StoreAPI> openStore()
{
    if (getEnv("NIX_REMOTE") == "")
        return boost::shared_ptr<StoreAPI>(new LocalStore());
    else
        return boost::shared_ptr<StoreAPI>(new RemoteStore());
}

}
<|endoftext|>


<commit_before>using namespace std;

#include "classes.h"

/**
    This file contains the functions which are used in the statistics component. Also contained is the function used for
    troublshooting, called "print_info", located at the very bottom of the file.
**/

void count_affiliations(ALL_Cards *all_cards, ALL_Cards *unique_affiliations, Affiliation_Array *aff_counter){

    /**
        Counts cards that share a specific set of affiliations.
        It will count both all cards in its database and the corresponding unique rarity profiles that
        have at least the specified affiliations
    **/

    int i,j,k, card_counter=0, unique_counter=0, tracker, rarity_tracker[5], unique_rarity_tracker[5];
    int print_choice, match_tracker[MAXCHARACTERS];

    for(i=0;i<5;i++){
        rarity_tracker[i]=0;
        unique_rarity_tracker[i]=0;
    }

    for(i=0;i<all_cards->number_of_characters;i++){
        tracker=0;
        for(j=0;j<all_cards->card[i].number_of_types;j++){
            for(k=0;k<aff_counter->number_of_affiliations;k++){
                if(aff_counter->affiliation[k].aff_name==all_cards->card[i].cardtype[j].affiliation){
                    tracker++;
                }
            }
        }
        if(tracker==aff_counter->number_of_affiliations){
            match_tracker[card_counter]=i;
            card_counter++;
            rarity_tracker[(all_cards->card[i].rarity)-1]++;
        }
    }

    for(i=0;i<unique_affiliations->number_of_characters;i++){
        tracker=0;
        for(j=0;j<unique_affiliations->card[i].number_of_types;j++){
            for(k=0;k<aff_counter->number_of_affiliations;k++){
                if(aff_counter->affiliation[k].aff_name==unique_affiliations->card[i].cardtype[j].affiliation){
                    tracker++;
                }
            }
        }
        if(tracker==aff_counter->number_of_affiliations){
            unique_counter++;
            unique_rarity_tracker[(unique_affiliations->card[i].rarity)-1]++;
        }
    }

    if(aff_counter->number_of_affiliations==1){
        cout << "\n\n\tNumber of Profiles with cardtype:  ";
    }else{
        cout << "\n\tNumber of Profiles possessing cardtypes:  ";
    }

    for(i=0;i<aff_counter->number_of_affiliations;i++){
        cout << aff_counter->affiliation[i].aff_name;
        if(i+1<aff_counter->number_of_affiliations){
            cout << " and ";
        }
    }

    cout << "\n";

    cout << "\n\t\tUnique: " << unique_counter << "  (";
    for(i=5;i>0;i--){
        cout << unique_rarity_tracker[i-1] << "  " << i << "*";
        if(i-1>0){
            cout << ",  ";
        }else{
            cout << ")" << "\n";
        }
    }
    cout << "\t\tCharacter: " << card_counter << "  (";

    for(i=5;i>0;i--){
        cout << rarity_tracker[i-1] << "  " << i << "*";
        if(i-1>0){
            cout << ",  ";
        }else{
            cout << ")" << "\n";
        }
    }

    cout << "\n\nPrint out Character names to txt file? (Yes = 1):  ";
    cin >> print_choice;

    if(!(cin.good()) || print_choice!=1){
        cin.clear();
        cin.ignore(256,'\n');
        print_choice=0;
    }

    if(print_choice==1){
        ofstream myoutput;
        string filename="CharacterProfiles/";

        filename.append(aff_counter->affiliation[0].aff_name);

        for(i=1;i<aff_counter->number_of_affiliations;i++){
            filename.append("_");
            filename.append(aff_counter->affiliation[i].aff_name);
        }

        filename.append(".txt");

        myoutput.open(filename.c_str());

        for(i=0;i<card_counter;i++){
            myoutput << all_cards->card[match_tracker[i]].name << "\n";
            myoutput << "\tRarity:  " << all_cards->card[match_tracker[i]].rarity << "\tCost:  " << all_cards->card[match_tracker[i]].cost;
            if(all_cards->card[match_tracker[i]].is_awakened){
                myoutput << "\tAwakened";
            }

            if(i+1<card_counter){
                myoutput << "\n\n";
            }
        }

        myoutput.close();

        cout << "\n\n\tCharacter names printed to 'CharacterProfiles'\n\n";
    }

}

void number_of_profiles(ALL_Cards *all_cards, ALL_Cards *unique_profiles){

    /** Counts all cards and all unique affiliations that are in the database and prints to screen **/

    cout << "\n\n\tThere are " << all_cards->number_of_characters << " total character cards and " << unique_profiles->number_of_characters << " unique affiliation profiles in this database\n";

}

void return_affiliation_numbers(ALL_Cards *all_cards, ALL_Cards *unique_profiles, int number){

    /** Counts and prints to screen all cards and unqiue profiles that have exactly N affiliations **/

    int i, counter=0, unique_counter=0;

    for(i=0;i<all_cards->number_of_characters;i++){
        if(all_cards->card[i].number_of_types==number){
            counter++;
        }
    }

    for(i=0;i<unique_profiles->number_of_characters;i++){
        if(unique_profiles->card[i].number_of_types==number){
            unique_counter++;
        }
    }

    cout << "\n\n\tThere are " << counter << " character cards and " << unique_counter << " unique profiles possessing " << number << " different types\n";

}

void print_rarity(ALL_Cards *all_cards, ALL_Cards *unique_affiliations){

    /** Counts and prints to screen the number of cards and unique profiles of each rarity **/

    int i, character_rarity[5], unique_rarity[5];

    for(i=0;i<5;i++){
        character_rarity[i]=0;
        unique_rarity[i]=0;
    }

    for(i=0;i<all_cards->number_of_characters;i++){
        character_rarity[all_cards->card[i].rarity-1]++;
    }

    for(i=0;i<unique_affiliations->number_of_characters;i++){
        unique_rarity[unique_affiliations->card[i].rarity-1]++;
    }

    cout << "\n\n";

    for(i=0;i<5;i++){
        cout << "\tThere are " << character_rarity[i] << " " << i+1 << "* character cards" ;
        cout << "  (" << unique_rarity[i] << " unique profiles)\n";
    }

    cout << "\n";
}

void track_awaken(ALL_Cards *all_cards, ALL_Cards *unique_affiliations){

    /** Counts and prints to screen the awakened cards in the database **/

    int i, character_awaken[5], unique_awaken[5];

    for(i=0;i<5;i++){
        character_awaken[i]=0;
        unique_awaken[i]=0;
    }

    for(i=0;i<all_cards->number_of_characters;i++){
        character_awaken[all_cards->card[i].rarity-1]+=all_cards->card[i].is_awakened;
    }

    for(i=0;i<unique_affiliations->number_of_characters;i++){
        unique_awaken[unique_affiliations->card[i].rarity-1]+=unique_affiliations->card[i].is_awakened;
    }

    cout << "\n\n";

    for(i=0;i<5;i++){
        cout << "\tThere are " << character_awaken[i] << " " << i+1 << "* awakened character cards" ;
        cout << "  (" << unique_awaken[i] << " unique awakened profiles)\n";
    }

    cout << "\n";

}

void count_affiliation_spread(ALL_Cards *all_cards, ALL_Cards *unique_affiliations){

    /**
        This function produces one output text file to the "UniqueProfiles" directory:
            "unique_profile_dist.txt"
                -Counts how many cards possess each unique affiliation profile
    **/

    int i,j,x,y, sum_tracker, sum_array_size=0;
    unsigned long int sum_array[MAXCHARACTERS][3];

    ofstream myoutput;

    sum_array[0][0]=all_cards->card[0].affiliation_sum;
    sum_array[0][1]=1;
    sum_array[0][2]=0;
    sum_array_size++;

    for(i=1;i<all_cards->number_of_characters;i++){
        sum_tracker=0;
        for(j=0;j<sum_array_size;j++){
            if(sum_array[j][0]!=all_cards->card[i].affiliation_sum){
                sum_tracker++;
            }else
                if(sum_array[j][0]==all_cards->card[i].affiliation_sum){
                    sum_array[j][1]++;
                }
        }
        if(sum_tracker==sum_array_size){
            sum_array[j][0]=all_cards->card[i].affiliation_sum;
            sum_array[j][1]=1;
            sum_array[j][2]=i;
            sum_array_size++;
        }

    }

    myoutput.open("UniqueProfiles/unique_profile_dist.txt");

    if(myoutput.is_open()==true){
        for(i=0;i<sum_array_size;i++){
            if(sum_array[i][1]==1){
                myoutput << "There is " << sum_array[i][1] << " character card whom is exactly: ";
            }else{
                myoutput << "There are " << sum_array[i][1] << " character cards who are exactly: ";
            }

            for(j=0;j<all_cards->card[sum_array[i][2]].number_of_types;j++){
                myoutput << all_cards->card[sum_array[i][2]].cardtype[j].affiliation;
                if(j+1<all_cards->card[sum_array[i][2]].number_of_types){
                    myoutput << ", ";
                }
            }

            if(i+1<sum_array_size){
                myoutput << "\n\n";
            }
        }

        myoutput.close();
    }

    cout << "\n\n\tAffiliation distributions printed to folder 'UniqueProfiles'\n";
}

void print_skills(AllSupportSkills allsupportskills){

    /**
        An interactive component. Main function is to print out information about support cards - names,
        rarity, requirements, max levels, etc. Two options: print by list or print by user choice
    **/

    int choice, skill_choice, i,j,k, list_on=1;

    cout << "\nPrint all skills (1) or choose from a list (2)?:  ";
    cin >> choice;

    while(!(cin.good()) || choice<1 || choice>2){
        cin.clear();
        cin.ignore(256,'\n');
        cout << "Invalid choice. Enter again:  ";
        cin >> choice;
    }
    cout << "\n\n";

    if(choice==1){
        for(i=0;i<allsupportskills.numberOfSkills;i++){
            cout << "\t" << allsupportskills.supportskill[i].skillName << ", Max Level: " << allsupportskills.supportskill[i].max_level << "\n";
            cout << "\n\tCards:\n";
            for(j=0;j<allsupportskills.supportskill[i].numberOfCards;j++){
                cout << "\t\t" << allsupportskills.supportskill[i].supportskillcard[j].rarity << "* " << allsupportskills.supportskill[i].supportskillcard[j].charactername << "\n";
                cout << "\t\t\trequires " << allsupportskills.supportskill[i].supportskillcard[j].numTypeReq << " cardtypes (";
                for(k=0;k<allsupportskills.supportskill[i].supportskillcard[j].numTypeReq;k++){
                    cout << allsupportskills.supportskill[i].supportskillcard[j].types_needed[k].affiliation;

                    if(k+1<allsupportskills.supportskill[i].supportskillcard[j].numTypeReq){
                        cout << " and ";
                    }else{
                        cout << ")\n";
                    }
                }
                cout << "\t\t\tCardType requirements per level: ";
                for(k=0;k<allsupportskills.supportskill[i].max_level;k++){
                    cout << allsupportskills.supportskill[i].supportskillcard[j].supportskillreqs[k].typereq;

                    if(k+1<allsupportskills.supportskill[i].max_level){
                        cout << "   ";
                    }
                }
                cout << "\n\n";
            }
            cout << "\nEnter any number to quit or enter any other value to continue ...\n";
            cin >> list_on;
            if(!(cin.good())){
                cin.clear();
                cin.ignore(256, '\n');
            }else{
                break;
            }
        }
    }else
        if(choice==2){
            do{
                for(i=0;i<allsupportskills.numberOfSkills;i++){
                    cout << i+1 << ")  " << allsupportskills.supportskill[i].skillName << "\n";
                }
                cout << "\nPlease choose a support skill:  ";
                cin >> skill_choice;

                while(!(cin.good()) || skill_choice>allsupportskills.numberOfSkills || skill_choice<1){
                    cin.clear();
                    cin.ignore(256, '\n');
                    cout << "\nInvalid choice. Please enter again:  ";
                    cin >> skill_choice;
                }

                i=skill_choice-1;

                cout << "\n\n\t" << allsupportskills.supportskill[i].skillName << ", Max Level: " << allsupportskills.supportskill[i].max_level << "\n";
                cout << "\n\tCards:\n";

                for(j=0;j<allsupportskills.supportskill[i].numberOfCards;j++){
                    cout << "\t\t" << allsupportskills.supportskill[i].supportskillcard[j].rarity << "* " << allsupportskills.supportskill[i].supportskillcard[j].charactername << "\n";
                    cout << "\t\t\trequires " << allsupportskills.supportskill[i].supportskillcard[j].numTypeReq << " cardtypes (";
                    for(k=0;k<allsupportskills.supportskill[i].supportskillcard[j].numTypeReq;k++){
                        cout << allsupportskills.supportskill[i].supportskillcard[j].types_needed[k].affiliation;

                        if(k+1<allsupportskills.supportskill[i].supportskillcard[j].numTypeReq){
                            cout << " and ";
                        }else{
                            cout << ")\n";
                        }
                    }
                    cout << "\t\t\tCardType requirements per level: ";
                    for(k=0;k<allsupportskills.supportskill[i].max_level;k++){
                        cout << allsupportskills.supportskill[i].supportskillcard[j].supportskillreqs[k].typereq;

                        if(k+1<allsupportskills.supportskill[i].max_level){
                            cout << "   ";
                        }
                    }
                    cout << "\n\n";
                }

                cout << "\nCheck another skill? (Yes = 1):  ";
                cin >> list_on;

                if(!(cin.good()) || list_on!=1){
                    cin.clear();
                    cin.ignore(256, '\n');
                    list_on=0;
                }

            }while(list_on==1);
        }

}

void print_exact_profiles(ALL_Cards *all_cards){

    /**
        Prints multiple text output to directory "CharacterProfiles/ExactProfiles"
        The files produced list the cards (name, rarity, cost, and awakened state)
        which possess the stated affiliations (the title of the text file). Output
        is only produced for combinations of affilations which exist in the database.
    **/

    int i,j,k,l, not_in_array=0, sum_size=0;
    unsigned long int affiliation_sum_tracker[MAXCHARACTERS], current_sum;
    string filename, txt=".txt";
    ofstream myoutput;

    for(i=0;i<all_cards->number_of_characters;i++){
        not_in_array=0;

        for(j=0;j<sum_size;j++){
            if(all_cards->card[i].affiliation_sum!=affiliation_sum_tracker[j]){
                not_in_array++;
            }
        }

        if(not_in_array==sum_size){
            current_sum=all_cards->card[i].affiliation_sum;

            filename="CharacterProfiles/ExactProfiles/";
            filename.append(all_cards->card[i].cardtype[0].affiliation);

            for(k=1;k<all_cards->card[i].number_of_types;k++){
                filename.append("_");
                filename.append(all_cards->card[i].cardtype[k].affiliation);
            }

            filename.append(txt);

            myoutput.open(filename.c_str());

            for(l=i;l<all_cards->number_of_characters;l++){
                if(all_cards->card[l].affiliation_sum==current_sum){
                    myoutput << all_cards->card[l].name << "\n";
                    myoutput << "Rarity: " << all_cards->card[l].rarity << "*\t\tCost: " << all_cards->card[l].cost << "\n\n";
                }
            }

            myoutput.close();

            affiliation_sum_tracker[sum_size]=current_sum;
            sum_size++;
        }
    }

    cout << "\n\n\tExact Profiles Updated.\n\n";
}

void check_stats(ALL_Cards *all_cards, ALL_Cards *unique_cards, Affiliation_Array *affiliation_array, AllSupportSkills *allsupportskills){

    /**
        This is the function which combines all the statistics components. This is called from main and it lets the
        user select which statistic they wish to run (or sometimes print) to text file output. It will run one selection
        and then ask if the user wishes to continue checking stats or if they're ready to proceed.
    **/

    int choice, finished=0, affiliation_number=0, keep_adding=0, translator, i, new_search;

    do{
        cout << "\n(1) Number of cards\n";
        cout << "(2) Number of cards of rarity X\n";
        cout << "(3) Number of Awakened Cards\n";
        cout << "(4) Number of cards who have exactly N affiliations\n";
        cout << "(5) Number of cards possessing exactly N specified affiliations\n";
        cout << "(6) Distribution of Affiliations\n";
        cout << "(7) List Support Abilities\n";
        cout << "(8) Update Exact Profiles\n";
        cout << "\nSelect which stat (1-8) you wish to check:  ";

        cin >> choice;

        while(!(cin.good()) || choice>8 || choice<1){
            cin.clear();
            cin.ignore(256,'\n');
            cout << "Invalid choice. Please enter again: ";
            cin >> choice;
        }

        if(choice==1){
            number_of_profiles(all_cards, unique_cards);
        }else
            if(choice==2){
                print_rarity(all_cards, unique_cards);
            }else
                if(choice==3){
                    track_awaken(all_cards, unique_cards);
                }else
                    if(choice==4){
                        cout << "\nExactly how many affiliations?: ";
                        cin >> affiliation_number;

                        while(!(cin.good()) || affiliation_number<0){
                            cin.clear();
                            cin.ignore(256,'\n');
                            cout << "Invalid choice. Please enter again: ";
                            cin >> affiliation_number;
                        }

                        return_affiliation_numbers(all_cards, unique_cards, affiliation_number);
                    }else
                        if(choice==5){
                            cout << "\n";
                            for(i=0;i<affiliation_array->number_of_affiliations;i++){
                                cout << right << setfill(' ') << setw(2) << i+1 << ")" << left << setw(23) << affiliation_array->affiliation[i].aff_name << "  ";

                                if(i%5==4){
                                    cout << "\n";
                                }
                            }

                            keep_adding=0;

                            cout << "\n\n\nSelect which affiliation(s) (1-" << affiliation_array->number_of_affiliations << ") you wish to search, then press enter\nEnter 0 to start search:\n";

                            do{
                                cin>>translator;

                                if(!(cin.good()) || translator<0 || translator>affiliation_array->number_of_affiliations){
                                    cin.clear();
                                    cin.ignore(256,'\n');
                                    cout << "\n\tInvalid entry\n";
                                }else
                                    if(translator==0){
                                        break;
                                    }else{
                                        new_search=0;

                                        for(i=0;i<keep_adding;i++){
                                            if(aff_counter.affiliation[i].type_value!=affiliation_array->affiliation[translator-1].type_value){
                                                new_search++;
                                            }
                                        }

                                        if(new_search==keep_adding){
                                            aff_counter.affiliation[keep_adding].aff_name=affiliation_array->affiliation[translator-1].aff_name;
                                            aff_counter.affiliation[keep_adding].type_value=affiliation_array->affiliation[translator-1].type_value;
                                            keep_adding++;
                                        }
                                    }

                                if(keep_adding==affiliation_array->number_of_affiliations){
                                    break;
                                }

                            }while(1==1);

                            aff_counter.number_of_affiliations=keep_adding;

                            cout << "\n";

                            count_affiliations(all_cards,unique_cards,&aff_counter);
                        }else
                            if(choice==6){
                                count_affiliation_spread(all_cards, unique_cards);
                            }else
                                if(choice==7){
                                    print_skills(*allsupportskills);
                                }else
                                    if(choice==8){
                                        print_exact_profiles(all_cards);
                                    }

        cout << "\n\nCheck more stats? (Yes = 1): ";
        cin >> finished;

        if(!(cin.good())){
            cin.clear();
            cin.ignore(256,'\n');
            finished=0;
        }

    }while(finished==1);

}

void print_info(AllSupportSkills *allsupportskills, ALL_Cards *all_cards){

    /**
        This component is the one mainly used for error checking. It is called directly from main, and it prints to screen
        information about the cards in the database: name, rarity, cost, awakened state, support skill, level requirements,
        affiliations, and their position in the database.

        When called, the user has the option to either list all the cards (sequential from position 0 to Max Character) or
        have them listed randomly.
    **/

    int x, i, counter, choice, rand_char, start, list_on=1;

    cout << "List (1) or random (2) or Quit (0)?: ";
    cin >> start;

    if(!(cin.good())){
        cin.clear();
        cin.ignore(256,'\n');
        start=0;
    }

    if(start==1){
        cout << endl;

        for(counter=0;counter<all_cards->number_of_characters;counter++){
            cout << all_cards->card[counter].rarity << "* " << all_cards->card[counter].name << " is afilliated with " << all_cards->card[counter].cardtype[0].affiliation;
            if(all_cards->card[counter].number_of_types>1){
                for(x=1;x<all_cards->card[counter].number_of_types;x++){
                    cout << " and " << all_cards->card[counter].cardtype[x].affiliation;
                }
            }
            cout << ".\n";

            if(all_cards->card[counter].is_awakened){
                cout << "This card can be awakened.\n";
            }else{
                cout << "This card cannot be awakened.\n";
            }

            if(all_cards->card[counter].has_skill){
                cout << all_cards->card[counter].rarity << "* " << all_cards->card[counter].name << " has skill " << all_cards->card[counter].skillname << ", which requires:\n";
                for(x=0;x<allsupportskills->supportskill[all_cards->card[counter].skill_ID].max_level;x++){
                    cout << "\t" << allsupportskills->supportskill[all_cards->card[counter].skill_ID].supportskillcard[all_cards->card[counter].skillcard_ID].supportskillreqs[x].typereq << " of ";
                    for(i=0;i<allsupportskills->supportskill[all_cards->card[counter].skill_ID].supportskillcard[all_cards->card[counter].skillcard_ID].numTypeReq;i++){
                        cout << "(" << allsupportskills->supportskill[all_cards->card[counter].skill_ID].supportskillcard[all_cards->card[counter].skillcard_ID].types_needed[i].affiliation << ")  ";
                    }
                    cout << " for level " <<  allsupportskills->supportskill[all_cards->card[counter].skill_ID].supportskillcard[all_cards->card[counter].skillcard_ID].supportskillreqs[x].level << endl;
                }
            }else{
                cout << all_cards->card[counter].rarity << "* " << all_cards->card[counter].name << " does not have a skill.\n";
            }
            cout << all_cards->card[counter].rarity << "* " << all_cards->card[counter].name << " costs " << all_cards->card[counter].cost << " points.\n";

            cout << "Database ID: " << counter << endl << endl;

            if(counter%15==14){
                cout << "\nInput any number to quit or any other value to continue ...\n";
                cin >> list_on;
                if(!(cin.good())){
                    cin.clear();
                    cin.ignore(256, '\n');
                }else{
                    break;
                }
            }
        }

    }else
        if(start==2){

            srand(time(NULL));

            do{
                rand_char=rand()%all_cards->number_of_characters;
                cout << "\n\n" << all_cards->card[rand_char].rarity << "* " << all_cards->card[rand_char].name << " is afilliated with " << all_cards->card[rand_char].cardtype[0].affiliation;
                    if(all_cards->card[rand_char].number_of_types>1){
                        for(x=1;x<all_cards->card[rand_char].number_of_types;x++){
                            cout << " and " << all_cards->card[rand_char].cardtype[x].affiliation;
                        }
                    }
                    cout << ".\n";

                    if(all_cards->card[rand_char].is_awakened){
                        cout << "This card can be awakened.\n";
                    }else{
                        cout << "This card cannot be awakened.\n";
                    }

                    if(all_cards->card[rand_char].has_skill){
                        cout << all_cards->card[rand_char].rarity << "* " << all_cards->card[rand_char].name << " has skill " << all_cards->card[rand_char].skillname << ", which requires:\n";
                        for(x=0;x<allsupportskills->supportskill[all_cards->card[rand_char].skill_ID].max_level;x++){
                            cout << "\t" << allsupportskills->supportskill[all_cards->card[rand_char].skill_ID].supportskillcard[all_cards->card[rand_char].skillcard_ID].supportskillreqs[x].typereq << " of ";
                            for(i=0;i<allsupportskills->supportskill[all_cards->card[rand_char].skill_ID].supportskillcard[all_cards->card[rand_char].skillcard_ID].numTypeReq;i++){
                                cout << "(" << allsupportskills->supportskill[all_cards->card[rand_char].skill_ID].supportskillcard[all_cards->card[rand_char].skillcard_ID].types_needed[i].affiliation << ")  ";
                            }
                            cout << " for level " <<  allsupportskills->supportskill[all_cards->card[rand_char].skill_ID].supportskillcard[all_cards->card[rand_char].skillcard_ID].supportskillreqs[x].level << endl;
                        }
                    }else{
                        cout << all_cards->card[rand_char].rarity << "* " << all_cards->card[rand_char].name << " does not have a skill.\n";
                    }
                    cout << all_cards->card[rand_char].rarity << "* " << all_cards->card[rand_char].name << " costs " << all_cards->card[rand_char].cost << " points.\n";

                cout << "Database ID: " << rand_char << endl;
                cout << "\n\nRun again? (Yes = 1):  ";
                cin >> choice;
                if(choice!=1){
                    cin.clear();
                    cin.ignore(256,'\n');
                    choice=0;
                }
                cout << "\n\n";

            }while(choice==1);
        }

    }
<commit_msg>Delete misc_functions.cpp<commit_after><|endoftext|>


<commit_before>
/*
    pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys.

    This file is part of pbrt.

    pbrt 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.  Note that the text contents of
    the book "Physically Based Rendering" are *not* licensed under the
    GNU GPL.

    pbrt 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, see <http://www.gnu.org/licenses/>.

 */

// lights/projection.cpp*
#include "lights/projection.h"
#include "montecarlo.h"
#include "paramset.h"
#include "imageio.h"

// ProjectionLight Method Definitions
ProjectionLight::ProjectionLight(const Transform &light2world,
        const Spectrum &intensity, const string &texname,
        float fov)
    : Light(light2world) {
    lightPos = LightToWorld(Point(0,0,0));
    Intensity = intensity;
    // Create _ProjectionLight_ MIP-map
    int width, height;
    RGBSpectrum *texels = ReadImage(texname, &width, &height);
    if (texels)
        projectionMap = new MIPMap<RGBSpectrum>(width, height, texels);
    else
        projectionMap = NULL;
    delete[] texels;

    // Initialize _ProjectionLight_ projection matrix
    float aspect = projectionMap ? float(width) / float(height) : 1.f;
    if (aspect > 1.f)  {
        screenX0 = -aspect; screenX1 = aspect;
        screenY0 = -1.f;    screenY1 = 1.f;
    }
    else {
        screenX0 = -1.f;            screenX1 = 1.f;
        screenY0 = -1.f / aspect;   screenY1 = 1.f / aspect;
    }
    hither = 1e-3f;
    yon = 1e30f;
    lightProjection = Perspective(fov, hither, yon);

    // Compute cosine of cone surrounding projection directions
    float opposite = tanf(Radians(fov) / 2.f);
    float tanDiag = opposite * sqrtf(1.f + 1.f/(aspect*aspect));
    cosTotalWidth = cosf(atanf(tanDiag));
}

ProjectionLight::~ProjectionLight() { delete projectionMap; }
Spectrum ProjectionLight::Sample_L(const Point &p, float pEpsilon,
         const LightSample &ls, float time, Vector *wi,
         float *pdf, VisibilityTester *visibility) const {
    *wi = Normalize(lightPos - p);
    *pdf = 1.f;
    visibility->SetSegment(p, pEpsilon, lightPos, 0., time);
    return Intensity * Projection(-*wi) /
        DistanceSquared(lightPos, p);
}

Spectrum ProjectionLight::Projection(const Vector &w) const {
    Vector wl = WorldToLight(w);
    // Discard directions behind projection light
    if (wl.z < hither) return 0.;

    // Project point onto projection plane and compute light
    Point Pl = lightProjection(Point(wl.x, wl.y, wl.z));
    if (Pl.x < screenX0 || Pl.x > screenX1 ||
        Pl.y < screenY0 || Pl.y > screenY1) return 0.;
    if (!projectionMap) return 1;
    float s = (Pl.x - screenX0) / (screenX1 - screenX0);
    float t = (Pl.y - screenY0) / (screenY1 - screenY0);
    return Spectrum(projectionMap->Lookup(s, t), SPECTRUM_ILLUMINANT);
}

Spectrum ProjectionLight::Power(const Scene *) const {
    return Spectrum(projectionMap->Lookup(.5f, .5f, .5f),
                    SPECTRUM_ILLUMINANT) *
        Intensity * 2.f * M_PI * (1.f - cosTotalWidth);
}

ProjectionLight *CreateProjectionLight(const Transform &light2world,
        const ParamSet &paramSet) {
    Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0));
    Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0));
    float fov = paramSet.FindOneFloat("fov", 45.);
    string texname = paramSet.FindOneString("mapname", "");
    return new ProjectionLight(light2world, I * sc, texname, fov);
}

Spectrum ProjectionLight::Sample_L(const Scene *scene, const LightSample &ls,
        float u1, float u2, float time, Ray *ray, Normal *Ns, float *pdf) const {
    Vector v = UniformSampleCone(ls.uPos[0], ls.uPos[1], cosTotalWidth);
    *ray = Ray(lightPos, LightToWorld(v), 0.f, INFINITY, time);
    *Ns = (Normal)ray->d;
    *pdf = UniformConePdf(cosTotalWidth);
    return Intensity * Projection(ray->d);
}

float ProjectionLight::Pdf(const Point &, const Vector &) const {
    return 0.;
}

<commit_msg>Fix crash in ProjectionLight::Power() when image didn't load successfully.<commit_after>
/*
    pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys.

    This file is part of pbrt.

    pbrt 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.  Note that the text contents of
    the book "Physically Based Rendering" are *not* licensed under the
    GNU GPL.

    pbrt 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, see <http://www.gnu.org/licenses/>.

 */

// lights/projection.cpp*
#include "lights/projection.h"
#include "montecarlo.h"
#include "paramset.h"
#include "imageio.h"

// ProjectionLight Method Definitions
ProjectionLight::ProjectionLight(const Transform &light2world,
        const Spectrum &intensity, const string &texname,
        float fov)
    : Light(light2world) {
    lightPos = LightToWorld(Point(0,0,0));
    Intensity = intensity;
    // Create _ProjectionLight_ MIP-map
    int width, height;
    RGBSpectrum *texels = ReadImage(texname, &width, &height);
    if (texels)
        projectionMap = new MIPMap<RGBSpectrum>(width, height, texels);
    else
        projectionMap = NULL;
    delete[] texels;

    // Initialize _ProjectionLight_ projection matrix
    float aspect = projectionMap ? float(width) / float(height) : 1.f;
    if (aspect > 1.f)  {
        screenX0 = -aspect; screenX1 = aspect;
        screenY0 = -1.f;    screenY1 = 1.f;
    }
    else {
        screenX0 = -1.f;            screenX1 = 1.f;
        screenY0 = -1.f / aspect;   screenY1 = 1.f / aspect;
    }
    hither = 1e-3f;
    yon = 1e30f;
    lightProjection = Perspective(fov, hither, yon);

    // Compute cosine of cone surrounding projection directions
    float opposite = tanf(Radians(fov) / 2.f);
    float tanDiag = opposite * sqrtf(1.f + 1.f/(aspect*aspect));
    cosTotalWidth = cosf(atanf(tanDiag));
}

ProjectionLight::~ProjectionLight() { delete projectionMap; }
Spectrum ProjectionLight::Sample_L(const Point &p, float pEpsilon,
         const LightSample &ls, float time, Vector *wi,
         float *pdf, VisibilityTester *visibility) const {
    *wi = Normalize(lightPos - p);
    *pdf = 1.f;
    visibility->SetSegment(p, pEpsilon, lightPos, 0., time);
    return Intensity * Projection(-*wi) /
        DistanceSquared(lightPos, p);
}

Spectrum ProjectionLight::Projection(const Vector &w) const {
    Vector wl = WorldToLight(w);
    // Discard directions behind projection light
    if (wl.z < hither) return 0.;

    // Project point onto projection plane and compute light
    Point Pl = lightProjection(Point(wl.x, wl.y, wl.z));
    if (Pl.x < screenX0 || Pl.x > screenX1 ||
        Pl.y < screenY0 || Pl.y > screenY1) return 0.;
    if (!projectionMap) return 1;
    float s = (Pl.x - screenX0) / (screenX1 - screenX0);
    float t = (Pl.y - screenY0) / (screenY1 - screenY0);
    return Spectrum(projectionMap->Lookup(s, t), SPECTRUM_ILLUMINANT);
}

Spectrum ProjectionLight::Power(const Scene *) const {
    return (projectionMap ? Spectrum(projectionMap->Lookup(.5f, .5f, .5f),
                                     SPECTRUM_ILLUMINANT) : Spectrum(1.f)) *
        Intensity * 2.f * M_PI * (1.f - cosTotalWidth);
}

ProjectionLight *CreateProjectionLight(const Transform &light2world,
        const ParamSet &paramSet) {
    Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0));
    Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0));
    float fov = paramSet.FindOneFloat("fov", 45.);
    string texname = paramSet.FindOneString("mapname", "");
    return new ProjectionLight(light2world, I * sc, texname, fov);
}

Spectrum ProjectionLight::Sample_L(const Scene *scene, const LightSample &ls,
        float u1, float u2, float time, Ray *ray, Normal *Ns, float *pdf) const {
    Vector v = UniformSampleCone(ls.uPos[0], ls.uPos[1], cosTotalWidth);
    *ray = Ray(lightPos, LightToWorld(v), 0.f, INFINITY, time);
    *Ns = (Normal)ray->d;
    *pdf = UniformConePdf(cosTotalWidth);
    return Intensity * Projection(ray->d);
}

float ProjectionLight::Pdf(const Point &, const Vector &) const {
    return 0.;
}

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief any server
///
/// @file
/// This file contains a server template.
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "AnyServer.h"

#ifdef TRI_HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif

#ifdef TRI_HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif

#include "ApplicationServer/ApplicationServer.h"
#include "Basics/FileUtils.h"
#include "Basics/logging.h"
#include "Basics/process-utils.h"

using namespace std;
using namespace triagens;
using namespace triagens::basics;
using namespace triagens::rest;

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief writes a pid file
////////////////////////////////////////////////////////////////////////////////

static void WritePidFile (string const& pidFile, int pid) {
  ofstream out(pidFile.c_str(), ios::trunc);

  if (! out) {
    LOG_FATAL_AND_EXIT("cannot write pid-file '%s'", pidFile.c_str());
  }

  out << pid;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a pid file
////////////////////////////////////////////////////////////////////////////////

static void CheckPidFile (string const& pidFile) {

  // check if the pid-file exists
  if (! pidFile.empty()) {
    if (FileUtils::isDirectory(pidFile)) {
      LOG_FATAL_AND_EXIT("pid-file '%s' is a directory", pidFile.c_str());
    }
    else if (FileUtils::exists(pidFile) && FileUtils::size(pidFile) > 0) {
      LOG_INFO("pid-file '%s' already exists, verifying pid", pidFile.c_str());

      ifstream f(pidFile.c_str());

      // file can be opened
      if (f) {
        TRI_pid_t oldPid;

        f >> oldPid;

        if (oldPid == 0) {
          LOG_FATAL_AND_EXIT("pid-file '%s' is unreadable", pidFile.c_str());
        }

        LOG_DEBUG("found old pid: %d", (int) oldPid);

#ifdef TRI_HAVE_FORK
        int r = kill(oldPid, 0);
#else
        int r = 0; // TODO for windows use TerminateProcess
#endif

        if (r == 0) {
          LOG_FATAL_AND_EXIT("pid-file '%s' exists and process with pid %d is still running", pidFile.c_str(), (int) oldPid);
        }
        else if (errno == EPERM) {
          LOG_FATAL_AND_EXIT("pid-file '%s' exists and process with pid %d is still running", pidFile.c_str(), (int) oldPid);
        }
        else if (errno == ESRCH) {
          LOG_ERROR("pid-file '%s exists, but no process with pid %d exists", pidFile.c_str(), (int) oldPid);

          if (! FileUtils::remove(pidFile)) {
            LOG_FATAL_AND_EXIT("pid-file '%s' exists, no process with pid %d exists, but pid-file cannot be removed", pidFile.c_str(), (int) oldPid);
          }

          LOG_INFO("removed stale pid-file '%s'", pidFile.c_str());
        }
        else {
          LOG_FATAL_AND_EXIT("pid-file '%s' exists and kill %d failed", pidFile.c_str(), (int) oldPid);
        }
      }

      // failed to open file
      else {
        LOG_FATAL_AND_EXIT("pid-file '%s' exists, but cannot be opened", pidFile.c_str());
      }
    }

    LOG_DEBUG("using pid-file '%s'", pidFile.c_str());
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief forks a new process
////////////////////////////////////////////////////////////////////////////////

#ifdef TRI_HAVE_FORK

static int ForkProcess (string const& workingDirectory, string& current) {

  // fork off the parent process
  TRI_pid_t pid = fork();

  if (pid < 0) {
    LOG_FATAL_AND_EXIT("cannot fork");
  }

  // Upon successful completion, fork() shall return 0 to the child process and
  // shall return the process ID of the child process to the parent process.

  // if we got a good PID, then we can exit the parent process
  if (pid > 0) {
    LOG_DEBUG("started child process with pid %d", (int) pid);
    return pid;
  }

  // change the file mode mask
  umask(0);

  // create a new SID for the child process
  TRI_pid_t sid = setsid();

  if (sid < 0) {
    LOG_FATAL_AND_EXIT("cannot create sid");
  }

  // store current working directory
  int err = 0;
  current = FileUtils::currentDirectory(&err);

  if (err != 0) {
    LOG_FATAL_AND_EXIT("cannot get current directory");
  }

  // change the current working directory (TODO must be configurable)
  if (! workingDirectory.empty()) {
    if (! FileUtils::changeDirectory(workingDirectory)) {
      LOG_FATAL_AND_EXIT("cannot change into working directory '%s'", workingDirectory.c_str());
    }
    else {
      LOG_INFO("changed working directory for child process to '%s'", workingDirectory.c_str());
    }
  }

  // we're a daemon so there won't be a terminal attached
  // close the standard file descriptors and re-open them mapped to /dev/null
  int fd = open("/dev/null", O_RDWR | O_CREAT, 0644);

  if (fd < 0) {
    LOG_FATAL_AND_EXIT("cannot open /dev/null");
  }

  if (dup2(fd, STDIN_FILENO) < 0) {
    LOG_FATAL_AND_EXIT("cannot re-map stdin to /dev/null");
  }

  if (dup2(fd, STDOUT_FILENO) < 0) {
    LOG_FATAL_AND_EXIT("cannot re-map stdout to /dev/null");
  }

  if (dup2(fd, STDERR_FILENO) < 0) {
    LOG_FATAL_AND_EXIT("cannot re-map stderr to /dev/null");
  }

  close(fd);

  return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief waits for the supervisor process with pid to return its exit status
/// waits for at most 5 seconds. if the supervisor has not returned until then,
/// we assume a successful start
////////////////////////////////////////////////////////////////////////////////

int WaitForSupervisor (int pid) {
  int tries = 0;

  while (++tries < 10) {
    int status;
    int res = waitpid(pid, &status, WNOHANG);

    if (res == -1) {
      // error in waitpid. don't know what to do
      break;
    }

    if (res != 0 && WIFEXITED(status)) {
      // give information about supervisor exit code
      if (WEXITSTATUS(status) == 0) {
        // exit code 0
        return EXIT_SUCCESS;
      }
      else if (WIFSIGNALED(status)) {
        switch (WTERMSIG(status)) {
          case 2:
          case 9:
          case 15:
            // terminated normally
            return EXIT_SUCCESS;
          default:
            break;
        }
      }

      // failure!
      LOG_ERROR("unable to start arangod. please check the logfiles for errors");
      return EXIT_FAILURE;
    }

    // sleep a while and retry
    usleep(500 * 1000);
  }

  // 5 seconds have elapsed... we now abort our loop
  return EXIT_SUCCESS;
}

#else

// ..............................................................................
// TODO: use windows API CreateProcess & CreateThread to minic fork()
// ..............................................................................

static int ForkProcess (string const& workingDirectory, string& current) {

  // fork off the parent process
  TRI_pid_t pid = -1; // fork();

  if (pid < 0) {
    LOG_FATAL_AND_EXIT("cannot fork");
  }

  return 0;
}

#endif

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

AnyServer::AnyServer ()
  : _mode(ServerMode::MODE_STANDALONE),
    _daemonMode(false),
    _supervisorMode(false),
    _pidFile(""),
    _workingDirectory(""),
    _applicationServer(nullptr) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

AnyServer::~AnyServer () {
  delete _applicationServer;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief starts the server
////////////////////////////////////////////////////////////////////////////////

int AnyServer::start () {
  startupProgress();

  if (_applicationServer == nullptr) {
    buildApplicationServer();
  }

  startupProgress();

  if (_supervisorMode) {
    return startupSupervisor();
  }
  else if (_daemonMode) {
    return startupDaemon();
  }
  else {
    _applicationServer->setupLogging(true, false, false);

    startupProgress();

    if (! _pidFile.empty()) {
      CheckPidFile(_pidFile);
      WritePidFile(_pidFile, TRI_CurrentProcessId());
    }

    startupProgress();

    int res = startupServer();

    if (! _pidFile.empty()) {
      if (! FileUtils::remove(_pidFile)) {
        LOG_DEBUG("cannot remove pid file '%s'", _pidFile.c_str());
      }
    }
    startupProgress();

    return res;
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief begins shutdown sequence
////////////////////////////////////////////////////////////////////////////////

void AnyServer::beginShutdown () {
  if (_applicationServer != nullptr) {
    _applicationServer->beginShutdown();
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                 protected methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief prepares the server for startup
////////////////////////////////////////////////////////////////////////////////

void AnyServer::prepareServer () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   private methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief starts a supervisor
////////////////////////////////////////////////////////////////////////////////

#ifdef TRI_HAVE_FORK

int AnyServer::startupSupervisor () {
  static time_t MIN_TIME_ALIVE_IN_SEC = 30;

  LOG_INFO("starting up in supervisor mode");

  CheckPidFile(_pidFile);

  _applicationServer->setupLogging(false, true, false);

  string current;
  int result = ForkProcess(_workingDirectory, current);

  // main process
  if (result != 0) {
    // wait for at most 5 seconds for the supervisor to return
    // if it returns within 5 seconds, we can fetch its exit code
    // and report it
    return WaitForSupervisor(result);
  }

  // child process
  else {
    setMode(ServerMode::MODE_SERVICE);

    time_t startTime = time(0);
    time_t t;
    bool done = false;
    result = 0;

    while (! done) {

      // fork of the server
      TRI_pid_t pid = fork();

      if (pid < 0) {
        TRI_EXIT_FUNCTION(EXIT_FAILURE, NULL);
      }

      // parent
      if (0 < pid) {
        _applicationServer->setupLogging(false, true, true);
        TRI_SetProcessTitle("arangodb [supervisor]");
        LOG_DEBUG("supervisor mode: within parent");

        int status;
        waitpid(pid, &status, 0);
        bool horrible = true;

        if (WIFEXITED(status)) {

          // give information about cause of death
          if (WEXITSTATUS(status) == 0) {
            LOG_INFO("child %d died of natural causes", (int) pid);
            done = true;
            horrible = false;
          }
          else {
            t = time(0) - startTime;

            LOG_ERROR("child %d died a horrible death, exit status %d", (int) pid, (int) WEXITSTATUS(status));

            if (t < MIN_TIME_ALIVE_IN_SEC) {
              LOG_ERROR("child only survived for %d seconds, this will not work - please fix the error first", (int) t);
              done = true;
            }
            else {
              done = false;
            }
          }
        }
        else if (WIFSIGNALED(status)) {
          switch (WTERMSIG(status)) {
            case 2:
            case 9:
            case 15:
              LOG_INFO("child %d died of natural causes, exit status %d", (int) pid, (int) WTERMSIG(status));
              done = true;
              horrible = false;
              break;

            default:
              t = time(0) - startTime;

              LOG_ERROR("child %d died a horrible death, signal %d", (int) pid, (int) WTERMSIG(status));

              if (t < MIN_TIME_ALIVE_IN_SEC) {
                LOG_ERROR("child only survived for %d seconds, this will not work - please fix the error first", (int) t);
                done = true;

#ifdef WCOREDUMP
                if (WCOREDUMP(status)) {
                  LOG_WARNING("child process %d produced a core dump", (int) pid);
                }
#endif
              }
              else {
                done = false;
              }

              break;
          }
        }
        else {
          LOG_ERROR("child %d died a horrible death, unknown cause", (int) pid);
          done = false;
        }

        // remove pid file
        if (horrible) {
          if (! FileUtils::remove(_pidFile)) {
            LOG_DEBUG("cannot remove pid file '%s'", _pidFile.c_str());
          }

          result = EXIT_FAILURE;
        }
      }

      // child
      else {
        _applicationServer->setupLogging(true, false, true);
        LOG_DEBUG("supervisor mode: within child");

        // write the pid file
        WritePidFile(_pidFile, TRI_CurrentProcessId());

        // force child to stop if supervisor dies
#ifdef TRI_HAVE_PRCTL
        prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
#endif

        // startup server
        prepareServer();
        result = startupServer();

        // remove pid file
        if (! FileUtils::remove(_pidFile)) {
          LOG_DEBUG("cannot remove pid file '%s'", _pidFile.c_str());
        }

        // and stop
        TRI_EXIT_FUNCTION(result, NULL);
      }
    }
  }

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief starts a daemon
////////////////////////////////////////////////////////////////////////////////

int AnyServer::startupDaemon () {
  LOG_INFO("starting up in daemon mode");

  CheckPidFile(_pidFile);

  _applicationServer->setupLogging(false, true, false);

  string current;
  int result = ForkProcess(_workingDirectory, current);

  // main process
  if (result != 0) {
    TRI_SetProcessTitle("arangodb [daemon]");
    WritePidFile(_pidFile, result);

    // issue #549: this is used as the exit code
    result = 0;
  }

  // child process
  else {
    setMode(ServerMode::MODE_SERVICE);
    _applicationServer->setupLogging(true, false, true);
    LOG_DEBUG("daemon mode: within child");

    // and startup server
    prepareServer();
    result = startupServer();

    // remove pid file
    if (! FileUtils::remove(_pidFile)) {
      LOG_DEBUG("cannot remove pid file '%s'", _pidFile.c_str());
    }
  }

  return result;
}

#else

int AnyServer::startupSupervisor () {
  return 0;
}

int AnyServer::startupDaemon () {
  return 0;
}

#endif

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>delay supervisor startup<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief any server
///
/// @file
/// This file contains a server template.
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "AnyServer.h"

#ifdef TRI_HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif

#ifdef TRI_HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif

#include "ApplicationServer/ApplicationServer.h"
#include "Basics/FileUtils.h"
#include "Basics/logging.h"
#include "Basics/process-utils.h"

using namespace std;
using namespace triagens;
using namespace triagens::basics;
using namespace triagens::rest;

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief writes a pid file
////////////////////////////////////////////////////////////////////////////////

static void WritePidFile (string const& pidFile, int pid) {
  ofstream out(pidFile.c_str(), ios::trunc);

  if (! out) {
    LOG_FATAL_AND_EXIT("cannot write pid-file '%s'", pidFile.c_str());
  }

  out << pid;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a pid file
////////////////////////////////////////////////////////////////////////////////

static void CheckPidFile (string const& pidFile) {

  // check if the pid-file exists
  if (! pidFile.empty()) {
    if (FileUtils::isDirectory(pidFile)) {
      LOG_FATAL_AND_EXIT("pid-file '%s' is a directory", pidFile.c_str());
    }
    else if (FileUtils::exists(pidFile) && FileUtils::size(pidFile) > 0) {
      LOG_INFO("pid-file '%s' already exists, verifying pid", pidFile.c_str());

      ifstream f(pidFile.c_str());

      // file can be opened
      if (f) {
        TRI_pid_t oldPid;

        f >> oldPid;

        if (oldPid == 0) {
          LOG_FATAL_AND_EXIT("pid-file '%s' is unreadable", pidFile.c_str());
        }

        LOG_DEBUG("found old pid: %d", (int) oldPid);

#ifdef TRI_HAVE_FORK
        int r = kill(oldPid, 0);
#else
        int r = 0; // TODO for windows use TerminateProcess
#endif

        if (r == 0) {
          LOG_FATAL_AND_EXIT("pid-file '%s' exists and process with pid %d is still running", pidFile.c_str(), (int) oldPid);
        }
        else if (errno == EPERM) {
          LOG_FATAL_AND_EXIT("pid-file '%s' exists and process with pid %d is still running", pidFile.c_str(), (int) oldPid);
        }
        else if (errno == ESRCH) {
          LOG_ERROR("pid-file '%s exists, but no process with pid %d exists", pidFile.c_str(), (int) oldPid);

          if (! FileUtils::remove(pidFile)) {
            LOG_FATAL_AND_EXIT("pid-file '%s' exists, no process with pid %d exists, but pid-file cannot be removed", pidFile.c_str(), (int) oldPid);
          }

          LOG_INFO("removed stale pid-file '%s'", pidFile.c_str());
        }
        else {
          LOG_FATAL_AND_EXIT("pid-file '%s' exists and kill %d failed", pidFile.c_str(), (int) oldPid);
        }
      }

      // failed to open file
      else {
        LOG_FATAL_AND_EXIT("pid-file '%s' exists, but cannot be opened", pidFile.c_str());
      }
    }

    LOG_DEBUG("using pid-file '%s'", pidFile.c_str());
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief forks a new process
////////////////////////////////////////////////////////////////////////////////

#ifdef TRI_HAVE_FORK

static int ForkProcess (string const& workingDirectory, string& current) {

  // fork off the parent process
  TRI_pid_t pid = fork();

  if (pid < 0) {
    LOG_FATAL_AND_EXIT("cannot fork");
  }

  // Upon successful completion, fork() shall return 0 to the child process and
  // shall return the process ID of the child process to the parent process.

  // if we got a good PID, then we can exit the parent process
  if (pid > 0) {
    LOG_DEBUG("started child process with pid %d", (int) pid);
    return pid;
  }

  // change the file mode mask
  umask(0);

  // create a new SID for the child process
  TRI_pid_t sid = setsid();

  if (sid < 0) {
    LOG_FATAL_AND_EXIT("cannot create sid");
  }

  // store current working directory
  int err = 0;
  current = FileUtils::currentDirectory(&err);

  if (err != 0) {
    LOG_FATAL_AND_EXIT("cannot get current directory");
  }

  // change the current working directory (TODO must be configurable)
  if (! workingDirectory.empty()) {
    if (! FileUtils::changeDirectory(workingDirectory)) {
      LOG_FATAL_AND_EXIT("cannot change into working directory '%s'", workingDirectory.c_str());
    }
    else {
      LOG_INFO("changed working directory for child process to '%s'", workingDirectory.c_str());
    }
  }

  // we're a daemon so there won't be a terminal attached
  // close the standard file descriptors and re-open them mapped to /dev/null
  int fd = open("/dev/null", O_RDWR | O_CREAT, 0644);

  if (fd < 0) {
    LOG_FATAL_AND_EXIT("cannot open /dev/null");
  }

  if (dup2(fd, STDIN_FILENO) < 0) {
    LOG_FATAL_AND_EXIT("cannot re-map stdin to /dev/null");
  }

  if (dup2(fd, STDOUT_FILENO) < 0) {
    LOG_FATAL_AND_EXIT("cannot re-map stdout to /dev/null");
  }

  if (dup2(fd, STDERR_FILENO) < 0) {
    LOG_FATAL_AND_EXIT("cannot re-map stderr to /dev/null");
  }

  close(fd);

  return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief waits for the supervisor process with pid to return its exit status
/// waits for at most 10 seconds. if the supervisor has not returned until then,
/// we assume a successful start
////////////////////////////////////////////////////////////////////////////////

int WaitForSupervisor (int pid) {
  if (! isatty(STDIN_FILENO)) {
    // during system boot, we don't have a tty, and we don't want to delay
    // the boot process
    return EXIT_SUCCESS;
  }

  // in case a tty is present, this is probably a manual invocation of the start
  // procedure
  double const end = TRI_microtime() + 10.0;

  while (TRI_microtime() < end) {
    int status;
    int res = waitpid(pid, &status, WNOHANG);

    if (res == -1) {
      // error in waitpid. don't know what to do
      break;
    }

    if (res != 0 && WIFEXITED(status)) {
      // give information about supervisor exit code
      if (WEXITSTATUS(status) == 0) {
        // exit code 0
        return EXIT_SUCCESS;
      }
      else if (WIFSIGNALED(status)) {
        switch (WTERMSIG(status)) {
          case 2:
          case 9:
          case 15:
            // terminated normally
            return EXIT_SUCCESS;
          default:
            break;
        }
      }

      // failure!
      LOG_ERROR("unable to start arangod. please check the logfiles for errors");
      return EXIT_FAILURE;
    }

    // sleep a while and retry
    usleep(500 * 1000);
  }

  // enough time has elapsed... we now abort our loop
  return EXIT_SUCCESS;
}

#else

// ..............................................................................
// TODO: use windows API CreateProcess & CreateThread to minic fork()
// ..............................................................................

static int ForkProcess (string const& workingDirectory, string& current) {

  // fork off the parent process
  TRI_pid_t pid = -1; // fork();

  if (pid < 0) {
    LOG_FATAL_AND_EXIT("cannot fork");
  }

  return 0;
}

#endif

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

AnyServer::AnyServer ()
  : _mode(ServerMode::MODE_STANDALONE),
    _daemonMode(false),
    _supervisorMode(false),
    _pidFile(""),
    _workingDirectory(""),
    _applicationServer(nullptr) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

AnyServer::~AnyServer () {
  delete _applicationServer;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief starts the server
////////////////////////////////////////////////////////////////////////////////

int AnyServer::start () {
  startupProgress();

  if (_applicationServer == nullptr) {
    buildApplicationServer();
  }

  startupProgress();

  if (_supervisorMode) {
    return startupSupervisor();
  }
  else if (_daemonMode) {
    return startupDaemon();
  }
  else {
    _applicationServer->setupLogging(true, false, false);

    startupProgress();

    if (! _pidFile.empty()) {
      CheckPidFile(_pidFile);
      WritePidFile(_pidFile, TRI_CurrentProcessId());
    }

    startupProgress();

    int res = startupServer();

    if (! _pidFile.empty()) {
      if (! FileUtils::remove(_pidFile)) {
        LOG_DEBUG("cannot remove pid file '%s'", _pidFile.c_str());
      }
    }
    startupProgress();

    return res;
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief begins shutdown sequence
////////////////////////////////////////////////////////////////////////////////

void AnyServer::beginShutdown () {
  if (_applicationServer != nullptr) {
    _applicationServer->beginShutdown();
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                 protected methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief prepares the server for startup
////////////////////////////////////////////////////////////////////////////////

void AnyServer::prepareServer () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   private methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief starts a supervisor
////////////////////////////////////////////////////////////////////////////////

#ifdef TRI_HAVE_FORK

int AnyServer::startupSupervisor () {
  static time_t MIN_TIME_ALIVE_IN_SEC = 30;

  LOG_INFO("starting up in supervisor mode");

  CheckPidFile(_pidFile);

  _applicationServer->setupLogging(false, true, false);

  string current;
  int result = ForkProcess(_workingDirectory, current);

  // main process
  if (result != 0) {
    // wait for a few seconds for the supervisor to return
    // if it returns within a reasonable time, we can fetch its exit code
    // and report it
    return WaitForSupervisor(result);
  }

  // child process
  else {
    setMode(ServerMode::MODE_SERVICE);

    time_t startTime = time(0);
    time_t t;
    bool done = false;
    result = 0;

    while (! done) {

      // fork of the server
      TRI_pid_t pid = fork();

      if (pid < 0) {
        TRI_EXIT_FUNCTION(EXIT_FAILURE, NULL);
      }

      // parent
      if (0 < pid) {
        _applicationServer->setupLogging(false, true, true);
        TRI_SetProcessTitle("arangodb [supervisor]");
        LOG_DEBUG("supervisor mode: within parent");

        int status;
        waitpid(pid, &status, 0);
        bool horrible = true;

        if (WIFEXITED(status)) {

          // give information about cause of death
          if (WEXITSTATUS(status) == 0) {
            LOG_INFO("child %d died of natural causes", (int) pid);
            done = true;
            horrible = false;
          }
          else {
            t = time(0) - startTime;

            LOG_ERROR("child %d died a horrible death, exit status %d", (int) pid, (int) WEXITSTATUS(status));

            if (t < MIN_TIME_ALIVE_IN_SEC) {
              LOG_ERROR("child only survived for %d seconds, this will not work - please fix the error first", (int) t);
              done = true;
            }
            else {
              done = false;
            }
          }
        }
        else if (WIFSIGNALED(status)) {
          switch (WTERMSIG(status)) {
            case 2:
            case 9:
            case 15:
              LOG_INFO("child %d died of natural causes, exit status %d", (int) pid, (int) WTERMSIG(status));
              done = true;
              horrible = false;
              break;

            default:
              t = time(0) - startTime;

              LOG_ERROR("child %d died a horrible death, signal %d", (int) pid, (int) WTERMSIG(status));

              if (t < MIN_TIME_ALIVE_IN_SEC) {
                LOG_ERROR("child only survived for %d seconds, this will not work - please fix the error first", (int) t);
                done = true;

#ifdef WCOREDUMP
                if (WCOREDUMP(status)) {
                  LOG_WARNING("child process %d produced a core dump", (int) pid);
                }
#endif
              }
              else {
                done = false;
              }

              break;
          }
        }
        else {
          LOG_ERROR("child %d died a horrible death, unknown cause", (int) pid);
          done = false;
        }

        // remove pid file
        if (horrible) {
          if (! FileUtils::remove(_pidFile)) {
            LOG_DEBUG("cannot remove pid file '%s'", _pidFile.c_str());
          }

          result = EXIT_FAILURE;
        }
      }

      // child
      else {
        _applicationServer->setupLogging(true, false, true);
        LOG_DEBUG("supervisor mode: within child");

        // write the pid file
        WritePidFile(_pidFile, TRI_CurrentProcessId());

        // force child to stop if supervisor dies
#ifdef TRI_HAVE_PRCTL
        prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
#endif

        // startup server
        prepareServer();
        result = startupServer();

        // remove pid file
        if (! FileUtils::remove(_pidFile)) {
          LOG_DEBUG("cannot remove pid file '%s'", _pidFile.c_str());
        }

        // and stop
        TRI_EXIT_FUNCTION(result, NULL);
      }
    }
  }

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief starts a daemon
////////////////////////////////////////////////////////////////////////////////

int AnyServer::startupDaemon () {
  LOG_INFO("starting up in daemon mode");

  CheckPidFile(_pidFile);

  _applicationServer->setupLogging(false, true, false);

  string current;
  int result = ForkProcess(_workingDirectory, current);

  // main process
  if (result != 0) {
    TRI_SetProcessTitle("arangodb [daemon]");
    WritePidFile(_pidFile, result);

    // issue #549: this is used as the exit code
    result = 0;
  }

  // child process
  else {
    setMode(ServerMode::MODE_SERVICE);
    _applicationServer->setupLogging(true, false, true);
    LOG_DEBUG("daemon mode: within child");

    // and startup server
    prepareServer();
    result = startupServer();

    // remove pid file
    if (! FileUtils::remove(_pidFile)) {
      LOG_DEBUG("cannot remove pid file '%s'", _pidFile.c_str());
    }
  }

  return result;
}

#else

int AnyServer::startupSupervisor () {
  return 0;
}

int AnyServer::startupDaemon () {
  return 0;
}

#endif

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before>/*

  Qt5xHb - Bindings libraries for Harbour/xHarbour and Qt Framework 5

  Copyright (C) 2019 Marcos Antonio Gambeta <marcosgambeta AT outlook DOT com>

*/

/*
  DO NOT EDIT THIS FILE - the content was created using a source code generator
*/

#include <Qt>

#ifndef __XHARBOUR__
#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
#include <QtWebViewVersion>
#endif
#endif

#include "qt5xhb_common.h"
#include "qt5xhb_macros.h"
#include "qt5xhb_utils.h"

#ifdef __XHARBOUR__
#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
#include <QtWebViewVersion>
#endif
#endif

HB_FUNC( QTWEBVIEW_VERSION_STR )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
  hb_retc( (const char *) QTWEBVIEW_VERSION_STR );
#else
  hb_retc( (const char *) "" );
#endif
}

HB_FUNC( QTWEBVIEW_VERSION )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
  hb_retni( QTWEBVIEW_VERSION );
#else
  hb_retni( 0 );
#endif
}
<commit_msg>source/QtWebView: 2019 -> 2020<commit_after>/*

  Qt5xHb - Bindings libraries for Harbour/xHarbour and Qt Framework 5

  Copyright (C) 2020 Marcos Antonio Gambeta <marcosgambeta AT outlook DOT com>

*/

/*
  DO NOT EDIT THIS FILE - the content was created using a source code generator
*/

#include <Qt>

#ifndef __XHARBOUR__
#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
#include <QtWebViewVersion>
#endif
#endif

#include "qt5xhb_common.h"
#include "qt5xhb_macros.h"
#include "qt5xhb_utils.h"

#ifdef __XHARBOUR__
#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
#include <QtWebViewVersion>
#endif
#endif

HB_FUNC( QTWEBVIEW_VERSION_STR )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
  hb_retc( (const char *) QTWEBVIEW_VERSION_STR );
#else
  hb_retc( (const char *) "" );
#endif
}

HB_FUNC( QTWEBVIEW_VERSION )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
  hb_retni( QTWEBVIEW_VERSION );
#else
  hb_retni( 0 );
#endif
}
<|endoftext|>