<commit_before>#include <iostream>
#include <cstring>
#include <cassert>

#include "ataxx.hpp"
#include "search.hpp"
#include "movegen.hpp"
#include "move.hpp"
#include "makemove.hpp"
#include "hashtable.hpp"
#include "pv.hpp"
#include "searchinfo.hpp"
#include "eval.hpp"
#include "score.hpp"
#include "zobrist.hpp"
#include "sorting.hpp"
#include "next-move.hpp"
#include "searchstack.hpp"
#include "other.hpp"

int reduction(const int move_num, const int depth)
{
    assert(move_num >= 0);
    assert(depth >= 0);

    if(move_num < 2 || depth < 3)
    {
        return 0;
    }

    if(move_num < 6)
    {
        return 1;
    }
    else if(move_num < 12)
    {
        return depth / 3;
    }
    else
    {
        return depth / 2;
    }
}

int alphabeta_search(const Position &pos, search_info &info, search_stack *ss, PV &pv, int alpha, int beta, int depth)
{
    assert(ss != NULL);
    assert(depth >= 0);
    assert(beta >= alpha);

    if(depth == 0 || info.depth >= MAX_DEPTH)
    {
        info.leaf_nodes++;
        return eval(pos);
    }

    if(info.nodes != 0)
    {
        // Stop searching if we've ran out of time
        if(*info.stop == true || clock() >= info.end)
        {
            return 0;
        }

        // Send an update on what we're doing
        if(info.nodes % 2000000 == 0)
        {
            double time_spent = (double)(clock() - info.start)/CLOCKS_PER_SEC;
            std::cout << "info"
                      << " nps " << (uint64_t)(info.nodes/time_spent)
                      << std::endl;
        }
    }

    int alpha_original = alpha;
    uint64_t key = generate_key(pos);
    Move tt_move = NO_MOVE;
    bool pvnode = (beta - alpha == 1);

    if(info.tt)
    {
        // Check the hash table
        Entry entry = probe(info.tt, key);
        if(key == entry.key)
        {
            tt_move = get_move(entry);

#ifndef NDEBUG
            info.hash_hits++;
            if(legal_move(pos, tt_move) == false)
            {
                info.hash_collisions++;
            }
#endif

            if(get_depth(entry) >= depth && legal_move(pos, tt_move) == true)
            {
                switch(get_flag(entry))
                {
                    case EXACT:
                        pv.num_moves = 1;
                        pv.moves[0] = tt_move;
                        return get_eval(entry);
                        break;
                    case LOWERBOUND:
                        alpha = (alpha > get_eval(entry) ? alpha : get_eval(entry));
                        break;
                    case UPPERBOUND:
                        beta = (beta < get_eval(entry) ? beta : get_eval(entry));
                        break;
                    default:
                        assert(false);
                        break;
                }

                if(alpha >= beta)
                {
                    pv.num_moves = 1;
                    pv.moves[0] = tt_move;
                    return get_eval(entry);
                }
            }
        }
    }

#ifdef NULLMOVE
    #define R (2)

    if(ss->nullmove && depth > 2 && !pvnode)
    {
        PV new_pv;

        Position new_pos = pos;
        new_pos.turn = !new_pos.turn;

        (ss+1)->nullmove = false;
        int score = -alphabeta_search(new_pos, info, ss+1, new_pv, -beta, -beta+1, depth-1-R);

        if(score >= beta)
        {
            return score;
        }
    }
    (ss+1)->nullmove = true;
#endif

    PV new_pv;
    Move best_move = NO_MOVE;
    int best_score = -INF;
    Move moves[256];
    int num_moves = movegen(pos, moves);

    // Score moves
    int scores[256] = {0};
    for(int n = 0; n < num_moves; ++n)
    {
        if(moves[n] == tt_move)
        {
            scores[n] = 10001;
        }
#ifdef KILLER_MOVES
        else if(moves[n] == ss->killer)
        {
            scores[n] = 10000;
        }
#endif
        else
        {
            scores[n] = count_captures(pos, moves[n]);

            scores[n] += (is_single(moves[n]) ? 1 : 0);
        }
    }

#ifdef IID
    if(tt_move == NO_MOVE && depth > 5)
    {
        int score = -alphabeta_search(pos, info, ss+1, new_pv, -beta, -alpha, depth-3);

        for(int n = 0; n < num_moves; ++n)
        {
            if(moves[n] == new_pv.moves[0])
            {
                scores[n] = 10001;
                break;
            }
        }
    }
#endif

    int move_num = 0;
    Move move = NO_MOVE;
    while(next_move(moves, num_moves, move, scores))
    {
        assert(move != NO_MOVE);
        Position new_pos = pos;

        makemove(new_pos, move);

        info.nodes++;

#ifdef FUTILITY_PRUNING
        int material = 100*(popcountll(new_pos.pieces[new_pos.turn]) - popcountll(new_pos.pieces[!new_pos.turn]));
        if(move_num > 0 && depth < 3 && -material + 100 < alpha)
        {
            continue;
        }
#endif

#ifdef LMR
        int r = reduction(move_num, depth);
        int score = -alphabeta_search(new_pos, info, ss+1, new_pv, -alpha-1, -alpha, depth-1-r);

        // Re-search
        if(score > alpha)
        {
            score = -alphabeta_search(new_pos, info, ss+1, new_pv, -beta, -alpha, depth-1);
        }
#else
        int score = -alphabeta_search(new_pos, info, ss+1, new_pv, -beta, -alpha, depth-1);
#endif

        if(score > best_score)
        {
            best_move = move;
            best_score = score;
        }

        if(score > alpha)
        {
            alpha = score;

            // Update PV
            pv.moves[0] = move;
            memcpy(pv.moves + 1, new_pv.moves, new_pv.num_moves * sizeof(Move));
            pv.num_moves = new_pv.num_moves + 1;
        }

        if(alpha >= beta)
        {
#ifdef KILLER_MOVES
            if(count_captures(pos, move) == 0)
            {
                ss->killer = move;
            }
#endif
#ifndef NDEBUG
            info.cutoffs[move_num]++;

            int num_captured = count_captures(pos, move);
            info.capture_cutoffs[num_captured]++;

            if(is_single(move) == true)
            {
                info.single_cutoffs++;
            }
            else
            {
                info.double_cutoffs++;
            }
#endif
            break;
        }

        move_num++;
    }

    if(num_moves == 0)
    {
        int val = score(pos);

        if(val > 0)
        {
            return INF - ss->ply;
        }
        else if(val < 0)
        {
            return -INF + ss->ply;
        }
        else
        {
            return (*info.options).contempt;
        }
    }

    if(info.tt)
    {
        uint8_t flag;
        if(best_score <= alpha_original)
        {
            flag = UPPERBOUND;
        }
        else if(best_score >= beta)
        {
            flag = LOWERBOUND;
        }
        else
        {
            flag = EXACT;
        }

        add(info.tt, key, depth, best_score, best_move, flag);
    }

#ifndef NDEBUG
    if(info.tt)
    {
        Entry test_entry = probe(info.tt, key);
        assert(test_entry.key == key);
        assert(test_entry.depth == depth);
        assert(test_entry.eval == best_score);
        assert(test_entry.move == best_move);
        assert(test_entry.flag == flag);
    }
#endif

    return best_score;
}
<commit_msg>Debug fix<commit_after>#include <iostream>
#include <cstring>
#include <cassert>

#include "ataxx.hpp"
#include "search.hpp"
#include "movegen.hpp"
#include "move.hpp"
#include "makemove.hpp"
#include "hashtable.hpp"
#include "pv.hpp"
#include "searchinfo.hpp"
#include "eval.hpp"
#include "score.hpp"
#include "zobrist.hpp"
#include "sorting.hpp"
#include "next-move.hpp"
#include "searchstack.hpp"
#include "other.hpp"

int reduction(const int move_num, const int depth)
{
    assert(move_num >= 0);
    assert(depth >= 0);

    if(move_num < 2 || depth < 3)
    {
        return 0;
    }

    if(move_num < 6)
    {
        return 1;
    }
    else if(move_num < 12)
    {
        return depth / 3;
    }
    else
    {
        return depth / 2;
    }
}

int alphabeta_search(const Position &pos, search_info &info, search_stack *ss, PV &pv, int alpha, int beta, int depth)
{
    assert(ss != NULL);
    assert(depth >= 0);
    assert(beta >= alpha);

    if(depth == 0 || info.depth >= MAX_DEPTH)
    {
        info.leaf_nodes++;
        return eval(pos);
    }

    if(info.nodes != 0)
    {
        // Stop searching if we've ran out of time
        if(*info.stop == true || clock() >= info.end)
        {
            return 0;
        }

        // Send an update on what we're doing
        if(info.nodes % 2000000 == 0)
        {
            double time_spent = (double)(clock() - info.start)/CLOCKS_PER_SEC;
            std::cout << "info"
                      << " nps " << (uint64_t)(info.nodes/time_spent)
                      << std::endl;
        }
    }

    int alpha_original = alpha;
    uint64_t key = generate_key(pos);
    Move tt_move = NO_MOVE;
    bool pvnode = (beta - alpha == 1);

    if(info.tt)
    {
        // Check the hash table
        Entry entry = probe(info.tt, key);
        if(key == entry.key)
        {
            tt_move = get_move(entry);

#ifndef NDEBUG
            info.hash_hits++;
            if(legal_move(pos, tt_move) == false)
            {
                info.hash_collisions++;
            }
#endif

            if(get_depth(entry) >= depth && legal_move(pos, tt_move) == true)
            {
                switch(get_flag(entry))
                {
                    case EXACT:
                        pv.num_moves = 1;
                        pv.moves[0] = tt_move;
                        return get_eval(entry);
                        break;
                    case LOWERBOUND:
                        alpha = (alpha > get_eval(entry) ? alpha : get_eval(entry));
                        break;
                    case UPPERBOUND:
                        beta = (beta < get_eval(entry) ? beta : get_eval(entry));
                        break;
                    default:
                        assert(false);
                        break;
                }

                if(alpha >= beta)
                {
                    pv.num_moves = 1;
                    pv.moves[0] = tt_move;
                    return get_eval(entry);
                }
            }
        }
    }

#ifdef NULLMOVE
    #define R (2)

    if(ss->nullmove && depth > 2 && !pvnode)
    {
        PV new_pv;

        Position new_pos = pos;
        new_pos.turn = !new_pos.turn;

        (ss+1)->nullmove = false;
        int score = -alphabeta_search(new_pos, info, ss+1, new_pv, -beta, -beta+1, depth-1-R);

        if(score >= beta)
        {
            return score;
        }
    }
    (ss+1)->nullmove = true;
#endif

    PV new_pv;
    Move best_move = NO_MOVE;
    int best_score = -INF;
    Move moves[256];
    int num_moves = movegen(pos, moves);

    // Score moves
    int scores[256] = {0};
    for(int n = 0; n < num_moves; ++n)
    {
        if(moves[n] == tt_move)
        {
            scores[n] = 10001;
        }
#ifdef KILLER_MOVES
        else if(moves[n] == ss->killer)
        {
            scores[n] = 10000;
        }
#endif
        else
        {
            scores[n] = count_captures(pos, moves[n]);

            scores[n] += (is_single(moves[n]) ? 1 : 0);
        }
    }

#ifdef IID
    if(tt_move == NO_MOVE && depth > 5)
    {
        int score = -alphabeta_search(pos, info, ss+1, new_pv, -beta, -alpha, depth-3);

        for(int n = 0; n < num_moves; ++n)
        {
            if(moves[n] == new_pv.moves[0])
            {
                scores[n] = 10001;
                break;
            }
        }
    }
#endif

    int move_num = 0;
    Move move = NO_MOVE;
    while(next_move(moves, num_moves, move, scores))
    {
        assert(move != NO_MOVE);
        Position new_pos = pos;

        makemove(new_pos, move);

        info.nodes++;

#ifdef FUTILITY_PRUNING
        int material = 100*(popcountll(new_pos.pieces[new_pos.turn]) - popcountll(new_pos.pieces[!new_pos.turn]));
        if(move_num > 0 && depth < 3 && -material + 100 < alpha)
        {
            continue;
        }
#endif

#ifdef LMR
        int r = reduction(move_num, depth);
        int score = -alphabeta_search(new_pos, info, ss+1, new_pv, -alpha-1, -alpha, depth-1-r);

        // Re-search
        if(score > alpha)
        {
            score = -alphabeta_search(new_pos, info, ss+1, new_pv, -beta, -alpha, depth-1);
        }
#else
        int score = -alphabeta_search(new_pos, info, ss+1, new_pv, -beta, -alpha, depth-1);
#endif

        if(score > best_score)
        {
            best_move = move;
            best_score = score;
        }

        if(score > alpha)
        {
            alpha = score;

            // Update PV
            pv.moves[0] = move;
            memcpy(pv.moves + 1, new_pv.moves, new_pv.num_moves * sizeof(Move));
            pv.num_moves = new_pv.num_moves + 1;
        }

        if(alpha >= beta)
        {
#ifdef KILLER_MOVES
            if(count_captures(pos, move) == 0)
            {
                ss->killer = move;
            }
#endif
#ifndef NDEBUG
            info.cutoffs[move_num]++;

            int num_captured = count_captures(pos, move);
            info.capture_cutoffs[num_captured]++;

            if(is_single(move) == true)
            {
                info.single_cutoffs++;
            }
            else
            {
                info.double_cutoffs++;
            }
#endif
            break;
        }

        move_num++;
    }

    if(num_moves == 0)
    {
        int val = score(pos);

        if(val > 0)
        {
            return INF - ss->ply;
        }
        else if(val < 0)
        {
            return -INF + ss->ply;
        }
        else
        {
            return (*info.options).contempt;
        }
    }

    uint8_t flag;
    if(info.tt)
    {
        if(best_score <= alpha_original)
        {
            flag = UPPERBOUND;
        }
        else if(best_score >= beta)
        {
            flag = LOWERBOUND;
        }
        else
        {
            flag = EXACT;
        }

        add(info.tt, key, depth, best_score, best_move, flag);
    }

#ifndef NDEBUG
    if(info.tt)
    {
        Entry test_entry = probe(info.tt, key);
        assert(test_entry.key == key);
        assert(test_entry.depth == depth);
        assert(test_entry.eval == best_score);
        assert(test_entry.move == best_move);
        assert(test_entry.flag == flag);
    }
#endif

    return best_score;
}
<|endoftext|>


<commit_before>#include <paths.h>
#include <sys/stat.h>
#include <stdio.h>
#include <cerrno>
#include <cstring>
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <string>
#include <stdio.h>
#include <string.h>
#include <sstream>
#include "../os.h"
#include "../../base/logger.h"

#include <mntent.h>
#include <dirent.h>
#include <sys/utsname.h>
#ifndef NDEBUG
#include <valgrind/memcheck.h>
#endif

#ifdef USE_DISK_MODEL
#define PARSE_ID_FUNC parse_disk_id
#define ID_FOLDER "/dev/disk/by-id/"
#else
#define PARSE_ID_FUNC parseUUID
#define ID_FOLDER "/dev/disk/by-uuid/"
#endif
#ifdef USE_DBUS
#include <dbus-1.0/dbus/dbus.h>
#endif

/**
 *Usually uuid are hex number separated by "-". this method read up to 8 hex
 *numbers skipping - characters.
 *@param uuid uuid as read in /dev/disk/by-uuid
 *@param buffer_out: unsigned char buffer[8] output buffer for result
 */
static void parseUUID(const char *uuid, unsigned char *buffer_out, unsigned int out_size) {
	unsigned int i, j;
	char *hexuuid;
	unsigned char cur_character;
	// remove characters not in hex set
	size_t len = strlen(uuid);
	hexuuid = (char *)malloc(sizeof(char) * len);
	memset(buffer_out, 0, out_size);
	memset(hexuuid, 0, sizeof(char) * len);

	for (i = 0, j = 0; i < len; i++) {
		if (isxdigit(uuid[i])) {
			hexuuid[j] = uuid[i];
			j++;
		} else {
			// skip
			continue;
		}
	}
	if (j % 2 == 1) {
		hexuuid[j++] = '0';
	}
	hexuuid[j] = '\0';
	for (i = 0; i < j / 2; i++) {
		sscanf(&hexuuid[i * 2], "%2hhx", &cur_character);
		buffer_out[i % out_size] = buffer_out[i % out_size] ^ cur_character;
	}

	free(hexuuid);
}

static void parse_disk_id(const char *uuid, unsigned char *buffer_out, size_t out_size) {
	unsigned int i;
	size_t len = strlen(uuid);
	memset(buffer_out, 0, out_size);
	for (i = 0; i < len; i++) {
		buffer_out[i % out_size] = buffer_out[i % out_size] ^ uuid[i];
	}
}

/**
 * 	int id;
	char device[MAX_PATH];
	unsigned char disk_sn[8];
	char label[255];
	int preferred;
 * @param blkidfile
 * @param diskInfos_out
 * @return
 */

static std::string getAttribute(const std::string &source, const std::string &attrName) {
	std::string attr_namefull = attrName + "=\"";
	std::size_t startpos = source.find(attr_namefull) + attr_namefull.size();
	std::size_t endpos = source.find("\"", startpos);
	return source.substr(startpos, endpos - startpos);
}

FUNCTION_RETURN parse_blkid(const std::string &blkid_file_content, std::vector<DiskInfo> &diskInfos_out) {
	DiskInfo diskInfo;
	int diskNum = 0;
	for (std::size_t oldpos = 0, pos = 0; (pos = blkid_file_content.find("</device>", oldpos)) != std::string::npos;
		 oldpos = pos + 1) {
		std::string cur_dev = blkid_file_content.substr(oldpos, pos);
		diskInfo.id = diskNum++;
		std::string device = cur_dev.substr(cur_dev.find_last_of(">") + 1);
		strncpy(diskInfo.device, device.c_str(), MAX_PATH);
		std::string label = getAttribute(cur_dev, "PARTLABEL");
		strncpy(diskInfo.label, label.c_str(), 255);
		std::string disk_sn = getAttribute(cur_dev, "UUID");
		parseUUID(disk_sn.c_str(), diskInfo.disk_sn, sizeof(diskInfo.disk_sn));
		std::string disk_type = getAttribute(cur_dev, "TYPE");
		// unlikely that somebody put the swap on a removable disk.
		// this is a first rough guess on what can be a preferred disk for blkid devices
		// just in case /etc/fstab can't be accessed or it is not up to date.
		diskInfo.preferred = (disk_type == "swap");
		diskInfos_out.push_back(diskInfo);
	}
	return FUNCTION_RETURN::FUNC_RET_OK;
}

#define BLKID_LOCATIONS {"/run/blkid/blkid.tab", "/etc/blkid.tab"};

static FUNCTION_RETURN getDiskInfos_blkid(std::vector<DiskInfo> &diskInfos) {
	const char *strs[] = BLKID_LOCATIONS;
	bool can_read = false;
	std::stringstream buffer;
	for (int i = 0; i < sizeof(strs) / sizeof(const char *); i++) {
		const char *location = strs[i];
		std::ifstream t(location);
		if (t.is_open()) {
			buffer << t.rdbuf();
			can_read = true;
			break;
		}
	}
	if (!can_read) {
		return FUNCTION_RETURN::FUNC_RET_NOT_AVAIL;
	}

	return parse_blkid(buffer.str(), diskInfos);
}

#define MAX_UNITS 40
FUNCTION_RETURN getDiskInfos_dev(std::vector<DiskInfo> &diskInfos) {
	struct dirent *dir = NULL;
	struct stat sym_stat;
	FUNCTION_RETURN result;

	DIR *disk_by_uuid_dir = opendir(ID_FOLDER);
	if (disk_by_uuid_dir == nullptr) {
		LOG_DEBUG("Open " ID_FOLDER " fail");
	} else {
		const std::string base_dir(ID_FOLDER "/");
		while ((dir = readdir(disk_by_uuid_dir)) != nullptr && diskInfos.size() < MAX_UNITS) {
			if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0 ||
				strncmp(dir->d_name, "usb", 3) == 0) {
				continue;
			}

			std::string cur_dir = base_dir + dir->d_name;
			if (stat(cur_dir.c_str(), &sym_stat) == 0) {
				DiskInfo tmpDiskInfo;
				tmpDiskInfo.id = sym_stat.st_ino;
				ssize_t len = ::readlink(cur_dir.c_str(), tmpDiskInfo.device, sizeof(tmpDiskInfo.device) - 1);
				if (len != -1) {
					tmpDiskInfo.device[len] = '\0';
					PARSE_ID_FUNC(dir->d_name, tmpDiskInfo.disk_sn, sizeof(tmpDiskInfo.disk_sn));
					tmpDiskInfo.sn_initialized = true;
					tmpDiskInfo.label_initialized = false;
					tmpDiskInfo.preferred = false;
					bool found = false;
					for (auto diskInfo : diskInfos) {
						if (tmpDiskInfo.id == diskInfo.id) {
							found = true;
							break;
						}
					}
					if (!found) {
						diskInfos.push_back(tmpDiskInfo);
					}
				} else {
					LOG_DEBUG("Error %s during readlink of %s", std::strerror(errno), cur_dir.c_str());
				}
			} else {
				LOG_DEBUG("Error %s during stat of %s", std::strerror(errno), cur_dir.c_str());
			}
		}
		closedir(disk_by_uuid_dir);
	}

	result = diskInfos.size() > 0 ? FUNCTION_RETURN::FUNC_RET_OK : FUNCTION_RETURN::FUNC_RET_NOT_AVAIL;
	const std::string label_dir("/dev/disk/by-label");
	DIR *disk_by_label = opendir(label_dir.c_str());
	if (disk_by_label != nullptr) {
		while ((dir = readdir(disk_by_label)) != nullptr) {
			if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
				continue;
			}
			std::string cur_disk_label = label_dir + "/" + dir->d_name;
			if (stat(cur_disk_label.c_str(), &sym_stat) == 0) {
				bool found = false;
				for (auto diskInfo : diskInfos) {
					if (((int)sym_stat.st_ino) == diskInfo.id) {
						strncpy(diskInfo.label, dir->d_name, 255 - 1);
						diskInfo.label_initialized = true;
						break;
					}
				}
			} else {
				LOG_DEBUG("Stat %s for fail:F %s", cur_disk_label, std::strerror(errno));
			}
		}
		closedir(disk_by_label);
	} else {
		LOG_DEBUG("Open %s for reading disk labels fail", label_dir);
	}

	return result;
}

/**
 * Try to determine removable devices: as a first guess removable devices doesn't have
 * an entry in /etc/fstab
 *
 * @param diskInfos
 */
static void set_preferred_disks(std::vector<DiskInfo> &diskInfos) {
	FILE *fstabFile = setmntent("/etc/fstab", "r");
	if (fstabFile == nullptr) {
		/*fstab not accessible*/
		return;
	}
	struct mntent *ent;
	while (nullptr != (ent = getmntent(fstabFile))) {
		bool found = false;
		for (auto disk_info : diskInfos) {
			if (strcmp(ent->mnt_fsname, disk_info.device) == 0) {
				disk_info.preferred = true;
				break;
			}
		}
	}
	endmntent(fstabFile);
	return;
}

/**
 * First try to read disk_infos from /dev/disk/by-id folder, if fails try to use
 * blkid cache to see what's in there, then try to exclude removable disks
 * looking at /etc/fstab
 * @param diskInfos_out vector used to output the disk informations
 * @return
 */
FUNCTION_RETURN getDiskInfos(std::vector<DiskInfo> &disk_infos) {
	FUNCTION_RETURN result = getDiskInfos_dev(disk_infos);
	if (result != FUNCTION_RETURN::FUNC_RET_OK) {
		result = getDiskInfos_blkid(disk_infos);
	}
	if (result == FUNCTION_RETURN::FUNC_RET_OK) {
		set_preferred_disks(disk_infos);
	}
	return result;
}

FUNCTION_RETURN getMachineName(unsigned char identifier[6]) {
	static struct utsname u;

	if (uname(&u) < 0) {
		return FUNC_RET_ERROR;
	}
	memcpy(identifier, u.nodename, 6);
	return FUNC_RET_OK;
}

FUNCTION_RETURN getOsSpecificIdentifier(unsigned char identifier[6]) {
#if USE_DBUS
	char *dbus_id = dbus_get_local_machine_id();
	if (dbus_id == NULL) {
		return FUNC_RET_ERROR;
	}
	memcpy(identifier, dbus_id, 6);
	dbus_free(dbus_id);
	return FUNC_RET_OK;
#else
	return FUNC_RET_NOT_AVAIL;
#endif
}

FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]) {
	FUNCTION_RETURN result;
	char path[MAX_PATH] = {0};
	char proc_path[MAX_PATH], pidStr[64];
	pid_t pid = getpid();
	sprintf(pidStr, "%d", pid);
	strcpy(proc_path, "/proc/");
	strcat(proc_path, pidStr);
	strcat(proc_path, "/exe");

	int ch = readlink(proc_path, path, MAX_PATH - 1);
	if (ch != -1) {
		path[ch] = '\0';
		strncpy(buffer, path, ch);
		result = FUNC_RET_OK;
	} else {
		result = FUNC_RET_ERROR;
	}
	return result;
}
<commit_msg>better logging<commit_after>#include <paths.h>
#include <sys/stat.h>
#include <stdio.h>
#include <cerrno>
#include <cstring>
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <string>
#include <stdio.h>
#include <string.h>
#include <sstream>
#include "../os.h"
#include "../../base/logger.h"

#include <mntent.h>
#include <dirent.h>
#include <sys/utsname.h>
#ifndef NDEBUG
#include <valgrind/memcheck.h>
#endif

#ifdef USE_DISK_MODEL
#define PARSE_ID_FUNC parse_disk_id
#define ID_FOLDER "/dev/disk/by-id"
#else
#define PARSE_ID_FUNC parseUUID
#define ID_FOLDER "/dev/disk/by-uuid"
#endif
#ifdef USE_DBUS
#include <dbus-1.0/dbus/dbus.h>
#endif

/**
 *Usually uuid are hex number separated by "-". this method read up to 8 hex
 *numbers skipping - characters.
 *@param uuid uuid as read in /dev/disk/by-uuid
 *@param buffer_out: unsigned char buffer[8] output buffer for result
 */
static void parseUUID(const char *uuid, unsigned char *buffer_out, unsigned int out_size) {
	unsigned int i, j;
	char *hexuuid;
	unsigned char cur_character;
	// remove characters not in hex set
	size_t len = strlen(uuid);
	hexuuid = (char *)malloc(sizeof(char) * len);
	memset(buffer_out, 0, out_size);
	memset(hexuuid, 0, sizeof(char) * len);

	for (i = 0, j = 0; i < len; i++) {
		if (isxdigit(uuid[i])) {
			hexuuid[j] = uuid[i];
			j++;
		} else {
			// skip
			continue;
		}
	}
	if (j % 2 == 1) {
		hexuuid[j++] = '0';
	}
	hexuuid[j] = '\0';
	for (i = 0; i < j / 2; i++) {
		sscanf(&hexuuid[i * 2], "%2hhx", &cur_character);
		buffer_out[i % out_size] = buffer_out[i % out_size] ^ cur_character;
	}

	free(hexuuid);
}

static void parse_disk_id(const char *uuid, unsigned char *buffer_out, size_t out_size) {
	unsigned int i;
	size_t len = strlen(uuid);
	memset(buffer_out, 0, out_size);
	for (i = 0; i < len; i++) {
		buffer_out[i % out_size] = buffer_out[i % out_size] ^ uuid[i];
	}
}

/**
 * 	int id;
	char device[MAX_PATH];
	unsigned char disk_sn[8];
	char label[255];
	int preferred;
 * @param blkidfile
 * @param diskInfos_out
 * @return
 */

static std::string getAttribute(const std::string &source, const std::string &attrName) {
	std::string attr_namefull = attrName + "=\"";
	std::size_t startpos = source.find(attr_namefull) + attr_namefull.size();
	std::size_t endpos = source.find("\"", startpos);
	return source.substr(startpos, endpos - startpos);
}

FUNCTION_RETURN parse_blkid(const std::string &blkid_file_content, std::vector<DiskInfo> &diskInfos_out) {
	DiskInfo diskInfo;
	int diskNum = 0;
	for (std::size_t oldpos = 0, pos = 0; (pos = blkid_file_content.find("</device>", oldpos)) != std::string::npos;
		 oldpos = pos + 1) {
		std::string cur_dev = blkid_file_content.substr(oldpos, pos);
		diskInfo.id = diskNum++;
		std::string device = cur_dev.substr(cur_dev.find_last_of(">") + 1);
		strncpy(diskInfo.device, device.c_str(), MAX_PATH);
		std::string label = getAttribute(cur_dev, "PARTLABEL");
		strncpy(diskInfo.label, label.c_str(), 255);
		std::string disk_sn = getAttribute(cur_dev, "UUID");
		parseUUID(disk_sn.c_str(), diskInfo.disk_sn, sizeof(diskInfo.disk_sn));
		std::string disk_type = getAttribute(cur_dev, "TYPE");
		// unlikely that somebody put the swap on a removable disk.
		// this is a first rough guess on what can be a preferred disk for blkid devices
		// just in case /etc/fstab can't be accessed or it is not up to date.
		diskInfo.preferred = (disk_type == "swap");
		diskInfos_out.push_back(diskInfo);
	}
	return FUNCTION_RETURN::FUNC_RET_OK;
}

#define BLKID_LOCATIONS {"/run/blkid/blkid.tab", "/etc/blkid.tab"};

static FUNCTION_RETURN getDiskInfos_blkid(std::vector<DiskInfo> &diskInfos) {
	const char *strs[] = BLKID_LOCATIONS;
	bool can_read = false;
	std::stringstream buffer;
	for (int i = 0; i < sizeof(strs) / sizeof(const char *); i++) {
		const char *location = strs[i];
		std::ifstream t(location);
		if (t.is_open()) {
			buffer << t.rdbuf();
			can_read = true;
			break;
		}
	}
	if (!can_read) {
		return FUNCTION_RETURN::FUNC_RET_NOT_AVAIL;
	}

	return parse_blkid(buffer.str(), diskInfos);
}

#define MAX_UNITS 40
FUNCTION_RETURN getDiskInfos_dev(std::vector<DiskInfo> &diskInfos) {
	struct dirent *dir = NULL;
	struct stat sym_stat;
	FUNCTION_RETURN result;

	DIR *disk_by_uuid_dir = opendir(ID_FOLDER);
	if (disk_by_uuid_dir == nullptr) {
		LOG_DEBUG("Open " ID_FOLDER " fail: %s", std::strerror(errno));
	} else {
		const std::string base_dir(ID_FOLDER "/");
		while ((dir = readdir(disk_by_uuid_dir)) != nullptr && diskInfos.size() < MAX_UNITS) {
			if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0 ||
				strncmp(dir->d_name, "usb", 3) == 0) {
				continue;
			}

			std::string cur_dir = base_dir + dir->d_name;
			if (stat(cur_dir.c_str(), &sym_stat) == 0) {
				DiskInfo tmpDiskInfo;
				tmpDiskInfo.id = sym_stat.st_ino;
				ssize_t len = ::readlink(cur_dir.c_str(), tmpDiskInfo.device, sizeof(tmpDiskInfo.device) - 1);
				if (len != -1) {
					tmpDiskInfo.device[len] = '\0';
					PARSE_ID_FUNC(dir->d_name, tmpDiskInfo.disk_sn, sizeof(tmpDiskInfo.disk_sn));
					tmpDiskInfo.sn_initialized = true;
					tmpDiskInfo.label_initialized = false;
					tmpDiskInfo.preferred = false;
					bool found = false;
					for (auto diskInfo : diskInfos) {
						if (tmpDiskInfo.id == diskInfo.id) {
							found = true;
							break;
						}
					}
					if (!found) {
						LOG_DEBUG("Found disk inode %d device %s, sn %s", sym_stat.st_ino, tmpDiskInfo.device,
								  dir->d_name);
						diskInfos.push_back(tmpDiskInfo);
					}
				} else {
					LOG_DEBUG("Error %s during readlink of %s", std::strerror(errno), cur_dir.c_str());
				}
			} else {
				LOG_DEBUG("Error %s during stat of %s", std::strerror(errno), cur_dir.c_str());
			}
		}
		closedir(disk_by_uuid_dir);
	}

	result = diskInfos.size() > 0 ? FUNCTION_RETURN::FUNC_RET_OK : FUNCTION_RETURN::FUNC_RET_NOT_AVAIL;
	const std::string label_dir("/dev/disk/by-label");
	DIR *disk_by_label = opendir(label_dir.c_str());
	if (disk_by_label != nullptr) {
		while ((dir = readdir(disk_by_label)) != nullptr) {
			if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
				continue;
			}
			std::string cur_disk_label = label_dir + "/" + dir->d_name;
			if (stat(cur_disk_label.c_str(), &sym_stat) == 0) {
				bool found = false;
				for (auto diskInfo : diskInfos) {
					if (((int)sym_stat.st_ino) == diskInfo.id) {
						strncpy(diskInfo.label, dir->d_name, 255 - 1);
						diskInfo.label_initialized = true;
						break;
					}
				}
			} else {
				LOG_DEBUG("Stat %s for fail:F %s", cur_disk_label.c_str(), std::strerror(errno));
			}
		}
		closedir(disk_by_label);
	} else {
		LOG_DEBUG("Open %s for reading disk labels fail: %s", label_dir.c_str(), std::strerror(errno));
	}

	return result;
}

/**
 * Try to determine removable devices: as a first guess removable devices doesn't have
 * an entry in /etc/fstab
 *
 * @param diskInfos
 */
static void set_preferred_disks(std::vector<DiskInfo> &diskInfos) {
	FILE *fstabFile = setmntent("/etc/fstab", "r");
	if (fstabFile == nullptr) {
		/*fstab not accessible*/
		return;
	}
	struct mntent *ent;
	while (nullptr != (ent = getmntent(fstabFile))) {
		bool found = false;
		for (auto disk_info : diskInfos) {
			if (strcmp(ent->mnt_fsname, disk_info.device) == 0) {
				disk_info.preferred = true;
				break;
			}
		}
	}
	endmntent(fstabFile);
	return;
}

/**
 * First try to read disk_infos from /dev/disk/by-id folder, if fails try to use
 * blkid cache to see what's in there, then try to exclude removable disks
 * looking at /etc/fstab
 * @param diskInfos_out vector used to output the disk informations
 * @return
 */
FUNCTION_RETURN getDiskInfos(std::vector<DiskInfo> &disk_infos) {
	FUNCTION_RETURN result = getDiskInfos_dev(disk_infos);
	if (result != FUNCTION_RETURN::FUNC_RET_OK) {
		result = getDiskInfos_blkid(disk_infos);
	}
	if (result == FUNCTION_RETURN::FUNC_RET_OK) {
		set_preferred_disks(disk_infos);
	}
	return result;
}

FUNCTION_RETURN getMachineName(unsigned char identifier[6]) {
	static struct utsname u;

	if (uname(&u) < 0) {
		return FUNC_RET_ERROR;
	}
	memcpy(identifier, u.nodename, 6);
	return FUNC_RET_OK;
}

FUNCTION_RETURN getOsSpecificIdentifier(unsigned char identifier[6]) {
#if USE_DBUS
	char *dbus_id = dbus_get_local_machine_id();
	if (dbus_id == NULL) {
		return FUNC_RET_ERROR;
	}
	memcpy(identifier, dbus_id, 6);
	dbus_free(dbus_id);
	return FUNC_RET_OK;
#else
	return FUNC_RET_NOT_AVAIL;
#endif
}

FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]) {
	FUNCTION_RETURN result;
	char path[MAX_PATH] = {0};
	char proc_path[MAX_PATH], pidStr[64];
	pid_t pid = getpid();
	sprintf(pidStr, "%d", pid);
	strcpy(proc_path, "/proc/");
	strcat(proc_path, pidStr);
	strcat(proc_path, "/exe");

	int ch = readlink(proc_path, path, MAX_PATH - 1);
	if (ch != -1) {
		path[ch] = '\0';
		strncpy(buffer, path, ch);
		result = FUNC_RET_OK;
	} else {
		result = FUNC_RET_ERROR;
	}
	return result;
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.15  2000/09/21 00:54:18  aruna1
 * OS2 related changes given by Bill Schindler
 *
 * Revision 1.14  2000/08/01 18:26:02  aruna1
 * Tru64 support added
 *
 * Revision 1.13  2000/07/18 18:25:58  andyh
 * Mac OS update.
 * Contributed by James Berry <jberry@criticalpath.com>
 *
 * Revision 1.12  2000/04/04 20:11:29  abagchi
 * Added PTX support
 *
 * Revision 1.11  2000/03/02 19:54:37  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.10  2000/03/02 01:51:00  aruna1
 * Sun CC 5.0 related changes
 *
 * Revision 1.9  2000/02/24 20:05:23  abagchi
 * Swat for removing Log from API docs
 *
 * Revision 1.8  2000/02/22 01:00:10  aruna1
 * GNUGDefs references removed. Now only GCCDefs is used instead
 *
 * Revision 1.7  2000/02/06 07:48:00  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.6  2000/02/01 23:43:22  abagchi
 * AS/400 related change
 *
 * Revision 1.5  2000/01/21 22:12:29  abagchi
 * OS390 Change: changed OE390 to OS390
 *
 * Revision 1.4  1999/12/18 00:47:01  rahulj
 * Merged in some changes for OS390.
 *
 * Revision 1.3  1999/12/17 01:28:53  rahulj
 * Merged in changes submitted for UnixWare 7 port. Platform
 * specific files are still missing.
 *
 * Revision 1.2  1999/12/01 17:16:16  rahulj
 * Added support for IRIX 6.5.5 using SGI MIPSpro C++ 7.3 and 7.21 generating 32 bit objects. Changes submitted by Marc Stuessel
 *
 * Revision 1.1.1.1  1999/11/09 01:03:55  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:45:03  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

#ifndef AUTOSENSE_HPP
#define AUTOSENSE_HPP

// ---------------------------------------------------------------------------
//  This section attempts to auto detect the operating system. It will set
//  up XercesC specific defines that are used by the rest of the code.
// ---------------------------------------------------------------------------
#if defined(_AIX)
    #define XML_AIX
    #define XML_UNIX
#elif defined(_SEQUENT_)
    #define XML_PTX
    #define XML_UNIX
#elif defined(_HP_UX) || defined(__hpux) || defined(_HPUX_SOURCE)
    #define XML_HPUX
    #define XML_UNIX
#elif defined(SOLARIS) || defined(__SVR4) || defined(UNIXWARE)
    #if defined(UNIXWARE)
        #define XML_UNIXWARE
        #define XML_CSET
        #define XML_SCOCC
        #define XML_UNIX
    #else
        #define XML_SOLARIS
        #define XML_UNIX
    #endif
#elif defined(__linux__)
    #define XML_LINUX
    #define XML_UNIX
#elif defined(IRIX)
    #define XML_IRIX
    #define XML_UNIX
#elif defined(__MVS__)
    #define XML_OS390
    #define XML_UNIX
#elif defined(EXM_OS390)
    #define XML_OS390
    #define XML_UNIX
#elif defined(__OS400__)
    #define XML_AS400
    #define XML_UNIX
#elif defined(__OS2__)
    #define XML_OS2
#elif defined(__TANDEM)
    #define XML_TANDEM
    #define XML_UNIX
    #define XML_CSET
#elif defined(_WIN32) || defined(WIN32)
    #define XML_WIN32
    #ifndef WIN32
      #define WIN32
    #endif
#elif defined(__WINDOWS__)

    // IBM VisualAge special handling
    #if defined(__32BIT__)
        #define XML_WIN32
    #else
        #define XML_WIN16
    #endif
#elif defined(__MSDXML__)
    #define XML_DOS

#elif defined(macintosh)
    #define XML_MACOS
#elif defined(MACOSX)
    #define XML_MACOSX
#elif defined(__alpha) && defined(__osf__)
    #define XML_TRU64
#else
    #error Code requires port to host OS!
#endif

// ---------------------------------------------------------------------------
//  This section attempts to autodetect the compiler being used. It will set
//  up Xerces specific defines that can be used by the rest of the code.
// ---------------------------------------------------------------------------
#if defined(_MSC_VER)
    #define XML_VISUALCPP
#elif defined(__BORLANDC__)
    #define XML_BORLAND
#elif defined(__xlC__)
    #define XML_CSET
#elif defined(XML_SOLARIS) || defined(XML_UNIXWARE)
    #if defined(__SUNPRO_CC) & __SUNPRO_CC >=0x500
        #define XML_SUNCC5
	#elif defined(__SUNPRO_CC) & __SUNPRO_CC <0x500
        #define XML_SUNCC
    #elif defined(_EDG_RUNTIME_USES_NAMESPACES)
        #define XML_SOLARIS_KAICC
    #elif defined(__GNUG__)
		#define XML_GCC
    #endif
#elif defined (__GNUG__) || defined(__linux__)
    #define XML_GCC
#elif defined(XML_HPUX)
    #if defined(EXM_HPUX)
        #define XML_HPUX_KAICC
    #elif (__cplusplus == 1)
        #define XML_HPUX_CC
    #elif (__cplusplus == 199707 || __cplusplus == 199711)
        #define XML_HPUX_aCC
    #endif
#elif defined(XML_IRIX)
    #define XML_MIPSPRO_CC
#elif defined(XML_PTX)
    #define XML_PTX_CC
#elif defined(XML_TANDEM)
    #define XML_TANDEMCC
#elif defined(__MVS__) && defined(__cplusplus)
    #define XML_MVSCPP
#elif defined(EXM_OS390) && defined(__cplusplus)
    #define XML_MVSCPP
#elif defined(__IBMC__) || defined(__IBMCPP__)
    #if defined(XML_WIN32)
        #define XML_IBMVAW32
    #elif defined(XML_OS2)
        #define XML_IBMVAOS2
        #if (__IBMC__ >= 400 || __IBMCPP__ >= 400)
            #define XML_IBMVA4_OS2
        #endif
    #endif
#elif defined(XML_TRU64) && defined(__DECCXX)
    #define XML_DECCXX
#elif defined(__MWERKS__)
    #define XML_METROWERKS
#elif defined(__OS400__)
#else
    #error Code requires port to current development environment
#endif

#endif
<commit_msg>Modify sensing of Mac OS X. PR: Obtained from: Submitted by: Reviewed by: PR: Obtained from: Submitted by: Reviewed by:<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.16  2000/10/09 18:15:43  jberry
 * Modify sensing of Mac OS X.
 * PR:
 * Obtained from:
 * Submitted by:
 * Reviewed by:
 * PR:
 * Obtained from:
 * Submitted by:
 * Reviewed by:
 *
 * Revision 1.15  2000/09/21 00:54:18  aruna1
 * OS2 related changes given by Bill Schindler
 *
 * Revision 1.14  2000/08/01 18:26:02  aruna1
 * Tru64 support added
 *
 * Revision 1.13  2000/07/18 18:25:58  andyh
 * Mac OS update.
 * Contributed by James Berry <jberry@criticalpath.com>
 *
 * Revision 1.12  2000/04/04 20:11:29  abagchi
 * Added PTX support
 *
 * Revision 1.11  2000/03/02 19:54:37  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.10  2000/03/02 01:51:00  aruna1
 * Sun CC 5.0 related changes
 *
 * Revision 1.9  2000/02/24 20:05:23  abagchi
 * Swat for removing Log from API docs
 *
 * Revision 1.8  2000/02/22 01:00:10  aruna1
 * GNUGDefs references removed. Now only GCCDefs is used instead
 *
 * Revision 1.7  2000/02/06 07:48:00  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.6  2000/02/01 23:43:22  abagchi
 * AS/400 related change
 *
 * Revision 1.5  2000/01/21 22:12:29  abagchi
 * OS390 Change: changed OE390 to OS390
 *
 * Revision 1.4  1999/12/18 00:47:01  rahulj
 * Merged in some changes for OS390.
 *
 * Revision 1.3  1999/12/17 01:28:53  rahulj
 * Merged in changes submitted for UnixWare 7 port. Platform
 * specific files are still missing.
 *
 * Revision 1.2  1999/12/01 17:16:16  rahulj
 * Added support for IRIX 6.5.5 using SGI MIPSpro C++ 7.3 and 7.21 generating 32 bit objects. Changes submitted by Marc Stuessel
 *
 * Revision 1.1.1.1  1999/11/09 01:03:55  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:45:03  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

#ifndef AUTOSENSE_HPP
#define AUTOSENSE_HPP

// ---------------------------------------------------------------------------
//  This section attempts to auto detect the operating system. It will set
//  up XercesC specific defines that are used by the rest of the code.
// ---------------------------------------------------------------------------
#if defined(_AIX)
    #define XML_AIX
    #define XML_UNIX
#elif defined(_SEQUENT_)
    #define XML_PTX
    #define XML_UNIX
#elif defined(_HP_UX) || defined(__hpux) || defined(_HPUX_SOURCE)
    #define XML_HPUX
    #define XML_UNIX
#elif defined(SOLARIS) || defined(__SVR4) || defined(UNIXWARE)
    #if defined(UNIXWARE)
        #define XML_UNIXWARE
        #define XML_CSET
        #define XML_SCOCC
        #define XML_UNIX
    #else
        #define XML_SOLARIS
        #define XML_UNIX
    #endif
#elif defined(__linux__)
    #define XML_LINUX
    #define XML_UNIX
#elif defined(IRIX)
    #define XML_IRIX
    #define XML_UNIX
#elif defined(__MVS__)
    #define XML_OS390
    #define XML_UNIX
#elif defined(EXM_OS390)
    #define XML_OS390
    #define XML_UNIX
#elif defined(__OS400__)
    #define XML_AS400
    #define XML_UNIX
#elif defined(__OS2__)
    #define XML_OS2
#elif defined(__TANDEM)
    #define XML_TANDEM
    #define XML_UNIX
    #define XML_CSET
#elif defined(_WIN32) || defined(WIN32)
    #define XML_WIN32
    #ifndef WIN32
      #define WIN32
    #endif
#elif defined(__WINDOWS__)

    // IBM VisualAge special handling
    #if defined(__32BIT__)
        #define XML_WIN32
    #else
        #define XML_WIN16
    #endif
#elif defined(__MSDXML__)
    #define XML_DOS

#elif defined(macintosh)
    #define XML_MACOS
#elif defined(__APPLE__) && defined(__MACH__)
    #define XML_MACOSX
#elif defined(__alpha) && defined(__osf__)
    #define XML_TRU64
#else
    #error Code requires port to host OS!
#endif

// ---------------------------------------------------------------------------
//  This section attempts to autodetect the compiler being used. It will set
//  up Xerces specific defines that can be used by the rest of the code.
// ---------------------------------------------------------------------------
#if defined(_MSC_VER)
    #define XML_VISUALCPP
#elif defined(__BORLANDC__)
    #define XML_BORLAND
#elif defined(__xlC__)
    #define XML_CSET
#elif defined(XML_SOLARIS) || defined(XML_UNIXWARE)
    #if defined(__SUNPRO_CC) & __SUNPRO_CC >=0x500
        #define XML_SUNCC5
	#elif defined(__SUNPRO_CC) & __SUNPRO_CC <0x500
        #define XML_SUNCC
    #elif defined(_EDG_RUNTIME_USES_NAMESPACES)
        #define XML_SOLARIS_KAICC
    #elif defined(__GNUG__)
		#define XML_GCC
    #endif
#elif defined (__GNUG__) || defined(__linux__)
    #define XML_GCC
#elif defined(XML_HPUX)
    #if defined(EXM_HPUX)
        #define XML_HPUX_KAICC
    #elif (__cplusplus == 1)
        #define XML_HPUX_CC
    #elif (__cplusplus == 199707 || __cplusplus == 199711)
        #define XML_HPUX_aCC
    #endif
#elif defined(XML_IRIX)
    #define XML_MIPSPRO_CC
#elif defined(XML_PTX)
    #define XML_PTX_CC
#elif defined(XML_TANDEM)
    #define XML_TANDEMCC
#elif defined(__MVS__) && defined(__cplusplus)
    #define XML_MVSCPP
#elif defined(EXM_OS390) && defined(__cplusplus)
    #define XML_MVSCPP
#elif defined(__IBMC__) || defined(__IBMCPP__)
    #if defined(XML_WIN32)
        #define XML_IBMVAW32
    #elif defined(XML_OS2)
        #define XML_IBMVAOS2
        #if (__IBMC__ >= 400 || __IBMCPP__ >= 400)
            #define XML_IBMVA4_OS2
        #endif
    #endif
#elif defined(XML_TRU64) && defined(__DECCXX)
    #define XML_DECCXX
#elif defined(__MWERKS__)
    #define XML_METROWERKS
#elif defined(__OS400__)
#else
    #error Code requires port to current development environment
#endif

#endif
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "syssocket.h" // this should be the first header included

#include "servicebrowser_p.h"

#include <QCoreApplication>
#include <QDebug>
#include <QFileInfo>
#include <QString>
#include <QStringList>
#include <QProcess>

#ifdef Q_OS_LINUX
#define EMBEDDED_LIB
#endif

#ifdef Q_OS_WIN32
#define EMBEDDED_LIB
#endif

#ifdef EMBEDDED_LIB
#define PID_FILE "/tmp/mdnsd.pid"
#define MDNS_UDS_SERVERPATH "/tmp/mdnsd"

#include "embed/dnssd_ipc.c"
#include "embed/dnssd_clientlib.c"
#include "embed/dnssd_clientstub.c"
#ifdef Q_OS_WIN
#include "embed/DebugServices.c"
#endif

namespace ZeroConf {
namespace Internal {
// represents a zero conf library exposing the dns-sd interface
class EmbeddedZConfLib : public ZConfLib
{
public:
    QString daemonPath;

    EmbeddedZConfLib(const QString &daemonPath, ZConfLib::Ptr fallBack) : ZConfLib(fallBack),
        daemonPath(daemonPath)
    {
        if (daemonPath.isEmpty())
            m_maxErrors = 0;
        if (!daemonPath.isEmpty() && daemonPath.at(0) != '/' && daemonPath.at(0) != '.')
            this->daemonPath = QCoreApplication::applicationDirPath() + QChar('/') + daemonPath;
    }

    ~EmbeddedZConfLib()
    { }

    QString name()
    {
        return QString::fromLatin1("EmbeddedZeroConfLib@%1").arg(size_t(this), 0, 16);
    }

    bool tryStartDaemon()
    {
        if (!daemonPath.isEmpty()) {
            QFileInfo dPath(daemonPath);
            QProcess killall;
            bool killAllFailed = false;
#ifdef Q_OS_WIN
            QString cmd = QLating1String("taskill /im ") + dPath.fileName()
                    + QLatin1String(" /f /t");
#else
            QString cmd = QLatin1String("killall ") + dPath.fileName()
                    + QLatin1String(" 2> /dev/null");
#endif
            killall.start(cmd);
            if (!killall.waitForStarted()) {
                killAllFailed = true;
            } else {
                killall.closeWriteChannel();
                killall.waitForFinished();
            }
            if (killAllFailed) {
                this->setError(false,ZConfLib::tr("zeroconf failed to kill other daemons with '%1'").arg(cmd));
                if (DEBUG_ZEROCONF)
                    qDebug() << name() << " had an error trying to kill other daemons with " << cmd;
            }
            if (QProcess::startDetached(daemonPath)) {
                QThread::yieldCurrentThread();
                // sleep a bit?
                if (DEBUG_ZEROCONF)
                    qDebug() << name() << " started " << daemonPath;
                return true;
            } else {
                this->setError(true, ZConfLib::tr("%1 failed starting embedded daemon at %2")
                               .arg(name()).arg(daemonPath));
            }
        }
        return false;
    }

    void refDeallocate(DNSServiceRef sdRef)
    {
        embeddedLib::DNSServiceRefDeallocate(sdRef);
    }

    void browserDeallocate(BrowserRef *bRef)
    {
        if (bRef){
            embeddedLib::DNSServiceRefDeallocate(*reinterpret_cast<DNSServiceRef*>(bRef));
            *bRef = 0;
        }
    }

    void stopConnection(ConnectionRef cRef)
    {
        int sock = refSockFD(cRef);
        if (sock>0)
            shutdown(sock, SHUT_RDWR);
    }

    void destroyConnection(ConnectionRef *sdRef)
    {
        if (sdRef) {
            embeddedLib::DNSServiceRefDeallocate(*reinterpret_cast<DNSServiceRef*>(sdRef));
            *sdRef = 0;
        }
    }

    DNSServiceErrorType resolve(ConnectionRef                       cRef,
                                DNSServiceRef                       *sdRef,
                                uint32_t                            interfaceIndex,
                                ZK_IP_Protocol                      /* protocol */,
                                const char                          *name,
                                const char                          *regtype,
                                const char                          *domain,
                                ServiceGatherer                     *gatherer)
    {
        *sdRef = reinterpret_cast<DNSServiceRef>(cRef);
        return embeddedLib::DNSServiceResolve(sdRef, kDNSServiceFlagsShareConnection
                                              // | kDNSServiceFlagsSuppressUnusable
                                              | kDNSServiceFlagsTimeout,
                                              interfaceIndex, name, regtype, domain,
                                              &cServiceResolveReply, gatherer);
    }

    DNSServiceErrorType queryRecord(ConnectionRef                       cRef,
                                    DNSServiceRef                       *sdRef,
                                    uint32_t                            interfaceIndex,
                                    const char                          *fullname,
                                    ServiceGatherer                     *gatherer)
    {
        *sdRef = reinterpret_cast<DNSServiceRef>(cRef);
        return embeddedLib::DNSServiceQueryRecord(sdRef, kDNSServiceFlagsShareConnection
                                                  // | kDNSServiceFlagsSuppressUnusable
                                                  | kDNSServiceFlagsTimeout,
                                                  interfaceIndex, fullname,
                                                  kDNSServiceType_TXT, kDNSServiceClass_IN,
                                                  &cTxtRecordReply , gatherer);
    }

    DNSServiceErrorType getAddrInfo(ConnectionRef                    cRef,
                                    DNSServiceRef                    *sdRef,
                                    uint32_t                         interfaceIndex,
                                    DNSServiceProtocol               protocol,
                                    const char                       *hostname,
                                    ServiceGatherer                  *gatherer)
    {
        *sdRef = reinterpret_cast<DNSServiceRef>(cRef);
        return embeddedLib::DNSServiceGetAddrInfo(sdRef, kDNSServiceFlagsShareConnection
                                                  // | kDNSServiceFlagsSuppressUnusable
                                                  | kDNSServiceFlagsTimeout,
                                                  interfaceIndex, protocol,
                                                  hostname, &cAddrReply, gatherer);
    }

    DNSServiceErrorType reconfirmRecord(ConnectionRef /*cRef*/, uint32_t /*interfaceIndex*/,
                                        const char * /*name*/, const char * /*type*/,
                                        const char * /*domain*/, const char * /*fullname*/)
    {
        // reload and force update with in the callback with
        // embeddedLib::DNSServiceReconfirmRecord(flags, interfaceIndex, fullname, rrtype,
        //     rrclass, rdlen, rdata);
        return kDNSServiceErr_Unsupported;
    }

    DNSServiceErrorType browse(ConnectionRef                       cRef,
                               BrowserRef                          *bRef,
                               uint32_t                            interfaceIndex,
                               const char                          *regtype,
                               const char                          *domain,    /* may be NULL */
                               ServiceBrowserPrivate               *browser)
    {
        DNSServiceRef *sdRef = reinterpret_cast<DNSServiceRef *>(bRef);
        *sdRef = reinterpret_cast<DNSServiceRef>(cRef);
        return embeddedLib::DNSServiceBrowse(sdRef, kDNSServiceFlagsShareConnection
                                             /* | kDNSServiceFlagsSuppressUnusable */,
                                             interfaceIndex, regtype, domain, &cBrowseReply,
                                             browser);
    }

    DNSServiceErrorType getProperty(const char *property, void *result, uint32_t *size)
    {
        return embeddedLib::DNSServiceGetProperty(property, result, size);
    }

    RunLoopStatus processOneEventBlock(ConnectionRef cRef)
    {
        if (embeddedLib::DNSServiceProcessResult(reinterpret_cast<DNSServiceRef>(cRef)) != kDNSServiceErr_NoError)
            return ProcessedError;
        return ProcessedOk;
    }

    DNSServiceErrorType createConnection(MainConnection *, ConnectionRef *sdRef)
    {
        return embeddedLib::DNSServiceCreateConnection(reinterpret_cast<DNSServiceRef*>(sdRef));
    }

    int refSockFD(ConnectionRef sdRef)
    {
        return embeddedLib::DNSServiceRefSockFD(reinterpret_cast<DNSServiceRef>(sdRef));
    }
};

ZConfLib::Ptr ZConfLib::createEmbeddedLib(const QString &daemonPath, const ZConfLib::Ptr &fallback)
{
    return ZConfLib::Ptr(new EmbeddedZConfLib(daemonPath, fallback));
}
} // namespace Internal
} // namespace ZeroConf

#else // no embedded lib

namespace ZeroConf {
namespace Internal {

ZConfLib::Ptr ZConfLib::createEmbeddedLib(const QString &, const ZConfLib::Ptr &fallback)
{
    return fallback;
}

} // namespace Internal
} // namespace ZeroConf
#endif
<commit_msg>zeroconf: fixing typo<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "syssocket.h" // this should be the first header included

#include "servicebrowser_p.h"

#include <QCoreApplication>
#include <QDebug>
#include <QFileInfo>
#include <QString>
#include <QStringList>
#include <QProcess>

#ifdef Q_OS_LINUX
#define EMBEDDED_LIB
#endif

#ifdef Q_OS_WIN32
#define EMBEDDED_LIB
#endif

#ifdef EMBEDDED_LIB
#define PID_FILE "/tmp/mdnsd.pid"
#define MDNS_UDS_SERVERPATH "/tmp/mdnsd"

#include "embed/dnssd_ipc.c"
#include "embed/dnssd_clientlib.c"
#include "embed/dnssd_clientstub.c"
#ifdef Q_OS_WIN
#include "embed/DebugServices.c"
#endif

namespace ZeroConf {
namespace Internal {
// represents a zero conf library exposing the dns-sd interface
class EmbeddedZConfLib : public ZConfLib
{
public:
    QString daemonPath;

    EmbeddedZConfLib(const QString &daemonPath, ZConfLib::Ptr fallBack) : ZConfLib(fallBack),
        daemonPath(daemonPath)
    {
        if (daemonPath.isEmpty())
            m_maxErrors = 0;
        if (!daemonPath.isEmpty() && daemonPath.at(0) != '/' && daemonPath.at(0) != '.')
            this->daemonPath = QCoreApplication::applicationDirPath() + QChar('/') + daemonPath;
    }

    ~EmbeddedZConfLib()
    { }

    QString name()
    {
        return QString::fromLatin1("EmbeddedZeroConfLib@%1").arg(size_t(this), 0, 16);
    }

    bool tryStartDaemon()
    {
        if (!daemonPath.isEmpty()) {
            QFileInfo dPath(daemonPath);
            QProcess killall;
            bool killAllFailed = false;
#ifdef Q_OS_WIN
            QString cmd = QLatin1String("taskill /im ") + dPath.fileName()
                    + QLatin1String(" /f /t");
#else
            QString cmd = QLatin1String("killall ") + dPath.fileName()
                    + QLatin1String(" 2> /dev/null");
#endif
            killall.start(cmd);
            if (!killall.waitForStarted()) {
                killAllFailed = true;
            } else {
                killall.closeWriteChannel();
                killall.waitForFinished();
            }
            if (killAllFailed) {
                this->setError(false,ZConfLib::tr("zeroconf failed to kill other daemons with '%1'").arg(cmd));
                if (DEBUG_ZEROCONF)
                    qDebug() << name() << " had an error trying to kill other daemons with " << cmd;
            }
            if (QProcess::startDetached(daemonPath)) {
                QThread::yieldCurrentThread();
                // sleep a bit?
                if (DEBUG_ZEROCONF)
                    qDebug() << name() << " started " << daemonPath;
                return true;
            } else {
                this->setError(true, ZConfLib::tr("%1 failed starting embedded daemon at %2")
                               .arg(name()).arg(daemonPath));
            }
        }
        return false;
    }

    void refDeallocate(DNSServiceRef sdRef)
    {
        embeddedLib::DNSServiceRefDeallocate(sdRef);
    }

    void browserDeallocate(BrowserRef *bRef)
    {
        if (bRef){
            embeddedLib::DNSServiceRefDeallocate(*reinterpret_cast<DNSServiceRef*>(bRef));
            *bRef = 0;
        }
    }

    void stopConnection(ConnectionRef cRef)
    {
        int sock = refSockFD(cRef);
        if (sock>0)
            shutdown(sock, SHUT_RDWR);
    }

    void destroyConnection(ConnectionRef *sdRef)
    {
        if (sdRef) {
            embeddedLib::DNSServiceRefDeallocate(*reinterpret_cast<DNSServiceRef*>(sdRef));
            *sdRef = 0;
        }
    }

    DNSServiceErrorType resolve(ConnectionRef                       cRef,
                                DNSServiceRef                       *sdRef,
                                uint32_t                            interfaceIndex,
                                ZK_IP_Protocol                      /* protocol */,
                                const char                          *name,
                                const char                          *regtype,
                                const char                          *domain,
                                ServiceGatherer                     *gatherer)
    {
        *sdRef = reinterpret_cast<DNSServiceRef>(cRef);
        return embeddedLib::DNSServiceResolve(sdRef, kDNSServiceFlagsShareConnection
                                              // | kDNSServiceFlagsSuppressUnusable
                                              | kDNSServiceFlagsTimeout,
                                              interfaceIndex, name, regtype, domain,
                                              &cServiceResolveReply, gatherer);
    }

    DNSServiceErrorType queryRecord(ConnectionRef                       cRef,
                                    DNSServiceRef                       *sdRef,
                                    uint32_t                            interfaceIndex,
                                    const char                          *fullname,
                                    ServiceGatherer                     *gatherer)
    {
        *sdRef = reinterpret_cast<DNSServiceRef>(cRef);
        return embeddedLib::DNSServiceQueryRecord(sdRef, kDNSServiceFlagsShareConnection
                                                  // | kDNSServiceFlagsSuppressUnusable
                                                  | kDNSServiceFlagsTimeout,
                                                  interfaceIndex, fullname,
                                                  kDNSServiceType_TXT, kDNSServiceClass_IN,
                                                  &cTxtRecordReply , gatherer);
    }

    DNSServiceErrorType getAddrInfo(ConnectionRef                    cRef,
                                    DNSServiceRef                    *sdRef,
                                    uint32_t                         interfaceIndex,
                                    DNSServiceProtocol               protocol,
                                    const char                       *hostname,
                                    ServiceGatherer                  *gatherer)
    {
        *sdRef = reinterpret_cast<DNSServiceRef>(cRef);
        return embeddedLib::DNSServiceGetAddrInfo(sdRef, kDNSServiceFlagsShareConnection
                                                  // | kDNSServiceFlagsSuppressUnusable
                                                  | kDNSServiceFlagsTimeout,
                                                  interfaceIndex, protocol,
                                                  hostname, &cAddrReply, gatherer);
    }

    DNSServiceErrorType reconfirmRecord(ConnectionRef /*cRef*/, uint32_t /*interfaceIndex*/,
                                        const char * /*name*/, const char * /*type*/,
                                        const char * /*domain*/, const char * /*fullname*/)
    {
        // reload and force update with in the callback with
        // embeddedLib::DNSServiceReconfirmRecord(flags, interfaceIndex, fullname, rrtype,
        //     rrclass, rdlen, rdata);
        return kDNSServiceErr_Unsupported;
    }

    DNSServiceErrorType browse(ConnectionRef                       cRef,
                               BrowserRef                          *bRef,
                               uint32_t                            interfaceIndex,
                               const char                          *regtype,
                               const char                          *domain,    /* may be NULL */
                               ServiceBrowserPrivate               *browser)
    {
        DNSServiceRef *sdRef = reinterpret_cast<DNSServiceRef *>(bRef);
        *sdRef = reinterpret_cast<DNSServiceRef>(cRef);
        return embeddedLib::DNSServiceBrowse(sdRef, kDNSServiceFlagsShareConnection
                                             /* | kDNSServiceFlagsSuppressUnusable */,
                                             interfaceIndex, regtype, domain, &cBrowseReply,
                                             browser);
    }

    DNSServiceErrorType getProperty(const char *property, void *result, uint32_t *size)
    {
        return embeddedLib::DNSServiceGetProperty(property, result, size);
    }

    RunLoopStatus processOneEventBlock(ConnectionRef cRef)
    {
        if (embeddedLib::DNSServiceProcessResult(reinterpret_cast<DNSServiceRef>(cRef)) != kDNSServiceErr_NoError)
            return ProcessedError;
        return ProcessedOk;
    }

    DNSServiceErrorType createConnection(MainConnection *, ConnectionRef *sdRef)
    {
        return embeddedLib::DNSServiceCreateConnection(reinterpret_cast<DNSServiceRef*>(sdRef));
    }

    int refSockFD(ConnectionRef sdRef)
    {
        return embeddedLib::DNSServiceRefSockFD(reinterpret_cast<DNSServiceRef>(sdRef));
    }
};

ZConfLib::Ptr ZConfLib::createEmbeddedLib(const QString &daemonPath, const ZConfLib::Ptr &fallback)
{
    return ZConfLib::Ptr(new EmbeddedZConfLib(daemonPath, fallback));
}
} // namespace Internal
} // namespace ZeroConf

#else // no embedded lib

namespace ZeroConf {
namespace Internal {

ZConfLib::Ptr ZConfLib::createEmbeddedLib(const QString &, const ZConfLib::Ptr &fallback)
{
    return fallback;
}

} // namespace Internal
} // namespace ZeroConf
#endif
<|endoftext|>


<commit_before>/*
  Copyright 2013 Larry Gritz and the other authors and contributors.
  All Rights Reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:
  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
  * Neither the name of the software's owners nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  (This is the Modified BSD License)
*/

#include <OpenEXR/half.h>

#include <cmath>
#include <iostream>
#include <stdexcept>

#include "OpenImageIO/imagebuf.h"
#include "OpenImageIO/imagebufalgo.h"
#include "OpenImageIO/imagebufalgo_util.h"
#include "OpenImageIO/dassert.h"
#include "OpenImageIO/thread.h"

OIIO_NAMESPACE_BEGIN

// Helper for flatten: identify channels in the spec that are important to
// deciphering deep images. Return true if appropriate alphas were found.
static bool
find_deep_channels (const ImageSpec &spec, int &alpha_channel,
                    int &RA_channel, int &GA_channel, int &BA_channel,
                    int &R_channel, int &G_channel, int &B_channel,
                    int &Z_channel, int &Zback_channel)
{
    static const char *names[] = { "A", "RA", "GA", "BA",
                                   "R", "G", "B", "Z", "Zback", NULL };
    int *chans[] = { &alpha_channel, &RA_channel, &GA_channel, &BA_channel,
                     &R_channel, &G_channel, &B_channel,
                     &Z_channel, &Zback_channel };
    for (int i = 0;  names[i];  ++i)
        *chans[i] = -1;
    for (int c = 0, e = int(spec.channelnames.size()); c < e; ++c) {
        for (int i = 0;  names[i];  ++i) {
            if (spec.channelnames[c] == names[i]) {
                *chans[i] = c;
                break;
            }
        }
    }
    if (Zback_channel < 0)
        Zback_channel = Z_channel;
    return (alpha_channel >= 0 ||
            (RA_channel >= 0 && GA_channel >= 0 && BA_channel >= 0));
}

// FIXME -- NOT CORRECT!  This code assumes sorted, non-overlapping samples.
// That is not a valid assumption in general. We will come back to fix this.
template<class DSTTYPE>
static bool
flatten_ (ImageBuf &dst, const ImageBuf &src,
          ROI roi, int nthreads)
{
    if (nthreads != 1 && roi.npixels() >= 1000) {
        // Possible multiple thread case -- recurse via parallel_image
        ImageBufAlgo::parallel_image (
            OIIO::bind(flatten_<DSTTYPE>, OIIO::ref(dst), OIIO::cref(src),
                        _1 /*roi*/, 1 /*nthreads*/),
            roi, nthreads);
        return true;
    }

    const ImageSpec &srcspec (src.spec());
    int nc = srcspec.nchannels;

    int alpha_channel, RA_channel, GA_channel, BA_channel;
    int R_channel, G_channel, B_channel;
    int Z_channel, Zback_channel;
    if (! find_deep_channels (srcspec, alpha_channel,
                              RA_channel, GA_channel, BA_channel,
                              R_channel, G_channel, B_channel,
                              Z_channel, Zback_channel)) {
        dst.error ("No alpha channel could be identified");
        return false;
    }
    ASSERT (alpha_channel >= 0 ||
            (RA_channel >= 0 && GA_channel >= 0 && BA_channel >= 0));
    float *val = ALLOCA (float, nc);
    float &RAval (RA_channel >= 0 ? val[RA_channel] : val[alpha_channel]);
    float &GAval (GA_channel >= 0 ? val[GA_channel] : val[alpha_channel]);
    float &BAval (BA_channel >= 0 ? val[BA_channel] : val[alpha_channel]);

    for (ImageBuf::Iterator<DSTTYPE> r (dst, roi);  !r.done();  ++r) {
        int x = r.x(), y = r.y(), z = r.z();
        int samps = src.deep_samples (x, y, z);
        // Clear accumulated values for this pixel (0 for colors, big for Z)
        memset (val, 0, nc*sizeof(float));
        if (Z_channel >= 0 && samps == 0)
            val[Z_channel] = 1.0e30;
        if (Zback_channel >= 0 && samps == 0)
            val[Zback_channel] = 1.0e30;
        for (int s = 0;  s < samps;  ++s) {
            float RA = RAval, GA = GAval, BA = BAval;  // make copies
            float alpha = (RA + GA + BA) / 3.0f;
            if (alpha >= 1.0f)
                break;
            for (int c = 0;  c < nc;  ++c) {
                float v = src.deep_value (x, y, z, c, s);
                if (c == Z_channel || c == Zback_channel)
                    val[c] *= alpha;  // because Z are not premultiplied
                float a;
                if (c == R_channel)
                    a = RA;
                else if (c == G_channel)
                    a = GA;
                else if (c == B_channel)
                    a = BA;
                else
                    a = alpha;
                val[c] += (1.0f - a) * v;
            }
        }

        for (int c = roi.chbegin;  c < roi.chend;  ++c)
            r[c] = val[c];
    }

    return true;
}

bool
ImageBufAlgo::flatten (ImageBuf &dst, const ImageBuf &src,
                       ROI roi, int nthreads)
{
    if (! src.deep()) {
        // For some reason, we were asked to flatten an already-flat image.
        // So just copy it.
        return dst.copy (src);
    }

    // Construct an ideal spec for dst, which is like src but not deep.
    ImageSpec force_spec = src.spec();
    force_spec.deep = false;
    force_spec.channelformats.clear();

    if (! IBAprep (roi, &dst, &src, NULL, &force_spec, IBAprep_SUPPORT_DEEP))
        return false;
    if (dst.spec().deep) {
        dst.error ("Cannot flatten to a deep image");
        return false;
    }

    const ImageSpec &srcspec (src.spec());
    int alpha_channel, RA_channel, GA_channel, BA_channel;
    int R_channel, G_channel, B_channel, Z_channel, Zback_channel;
    if (! find_deep_channels (srcspec, alpha_channel,
                              RA_channel, GA_channel, BA_channel,
                              R_channel, G_channel, B_channel,
                              Z_channel, Zback_channel)) {
        dst.error ("No alpha channel could be identified");
        return false;
    }

    bool ok;
    OIIO_DISPATCH_TYPES (ok, "flatten", flatten_, dst.spec().format,
                         dst, src, roi, nthreads);
    return ok;
}

bool
ImageBufAlgo::deepen (ImageBuf &dst, const ImageBuf &src, float zvalue,
                      ROI roi, int nthreads)
{
    if (src.deep()) {
        // For some reason, we were asked to deepen an already-deep image.
        // So just copy it.
        return dst.copy (src);
        // FIXME: once paste works for deep files, this should really be
        // return paste (dst, roi.xbegin, roi.ybegin, roi.zbegin, roi.chbegin,
        //               src, roi, nthreads);
    }

    // Construct an ideal spec for dst, which is like src but deep.
    const ImageSpec &srcspec (src.spec());
    int nc = srcspec.nchannels;
    int zback_channel = -1;
    ImageSpec force_spec = srcspec;
    force_spec.deep = true;
    force_spec.set_format (TypeDesc::FLOAT);
    force_spec.channelformats.clear();
    for (int c = 0; c < nc; ++c) {
        if (force_spec.channelnames[c] == "Z")
            force_spec.z_channel = c;
        else if (force_spec.channelnames[c] == "Zback")
            zback_channel = c;
    }
    bool add_z_channel = (force_spec.z_channel < 0);
    if (add_z_channel) {
        // No z channel? Make one.
        force_spec.z_channel = force_spec.nchannels++;
        force_spec.channelnames.push_back ("Z");
    }

    if (! IBAprep (roi, &dst, &src, NULL, &force_spec, IBAprep_SUPPORT_DEEP))
        return false;
    if (! dst.deep()) {
        dst.error ("Cannot deepen to a flat image");
        return false;
    }

    float *pixel = OIIO_ALLOCA (float, nc);

    // First, figure out which pixels get a sample and which do not
    for (int z = roi.zbegin; z < roi.zend; ++z)
    for (int y = roi.ybegin; y < roi.yend; ++y)
    for (int x = roi.xbegin; x < roi.xend; ++x) {
        bool has_sample = false;
        src.getpixel (x, y, z, pixel);
        for (int c = 0; c < nc; ++c)
            if (c != force_spec.z_channel && c != zback_channel
                  && pixel[c] != 0.0f) {
                has_sample = true;
                break;
            }
        if (! has_sample && ! add_z_channel)
            for (int c = 0; c < nc; ++c)
                if ((c == force_spec.z_channel || c == zback_channel)
                    && (pixel[c] != 0.0f && pixel[c] < 1e30)) {
                    has_sample = true;
                    break;
                }
        if (has_sample)
            dst.set_deep_samples (x, y, z, 1);
    }

    dst.deep_alloc ();

    // Now actually set the values
    for (int z = roi.zbegin; z < roi.zend; ++z)
    for (int y = roi.ybegin; y < roi.yend; ++y)
    for (int x = roi.xbegin; x < roi.xend; ++x) {
        if (dst.deep_samples (x, y, z) == 0)
            continue;
        for (int c = 0; c < nc; ++c)
            dst.set_deep_value (x, y, z, c, 0 /*sample*/,
                                src.getchannel (x, y, z, c));
        if (add_z_channel)
            dst.set_deep_value (x, y, z, nc, 0, zvalue);
    }

    bool ok = true;
    // FIXME -- the above doesn't split into threads. Someday, it should
    // be refactored like this:
    // OIIO_DISPATCH_COMMON_TYPES2 (ok, "deepen", deepen_,
    //                              dst.spec().format, srcspec.format,
    //                              dst, src, add_z_channel, z, roi, nthreads);
    return ok;
}

OIIO_NAMESPACE_END
<commit_msg>Deep OpenEXR: recognize newer AR/AG/AB channel name convention.<commit_after>/*
  Copyright 2013 Larry Gritz and the other authors and contributors.
  All Rights Reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:
  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
  * Neither the name of the software's owners nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  (This is the Modified BSD License)
*/

#include <OpenEXR/half.h>

#include <cmath>
#include <iostream>
#include <stdexcept>

#include "OpenImageIO/imagebuf.h"
#include "OpenImageIO/imagebufalgo.h"
#include "OpenImageIO/imagebufalgo_util.h"
#include "OpenImageIO/dassert.h"
#include "OpenImageIO/thread.h"

OIIO_NAMESPACE_BEGIN

// Helper for flatten: identify channels in the spec that are important to
// deciphering deep images. Return true if appropriate alphas were found.
static bool
find_deep_channels (const ImageSpec &spec, int &alpha_channel,
                    int &AR_channel, int &AG_channel, int &AB_channel,
                    int &R_channel, int &G_channel, int &B_channel,
                    int &Z_channel, int &Zback_channel)
{
    static const char *names[] = { "A",
                                   "RA", "GA", "BA", // old OpenEXR recommendation
                                   "AR", "AG", "AB", // new OpenEXR recommendation
                                   "R", "G", "B",
                                   "Z", "Zback", NULL };
    int *chans[] = { &alpha_channel,
                     &AR_channel, &AG_channel, &AB_channel,
                     &AR_channel, &AG_channel, &AB_channel,
                     &R_channel, &G_channel, &B_channel,
                     &Z_channel, &Zback_channel };
    for (int i = 0;  names[i];  ++i)
        *chans[i] = -1;
    for (int c = 0, e = int(spec.channelnames.size()); c < e; ++c) {
        for (int i = 0;  names[i];  ++i) {
            if (spec.channelnames[c] == names[i]) {
                *chans[i] = c;
                break;
            }
        }
    }
    if (Zback_channel < 0)
        Zback_channel = Z_channel;
    return (alpha_channel >= 0 ||
            (AR_channel >= 0 && AG_channel >= 0 && AB_channel >= 0));
}

// FIXME -- NOT CORRECT!  This code assumes sorted, non-overlapping samples.
// That is not a valid assumption in general. We will come back to fix this.
template<class DSTTYPE>
static bool
flatten_ (ImageBuf &dst, const ImageBuf &src,
          ROI roi, int nthreads)
{
    if (nthreads != 1 && roi.npixels() >= 1000) {
        // Possible multiple thread case -- recurse via parallel_image
        ImageBufAlgo::parallel_image (
            OIIO::bind(flatten_<DSTTYPE>, OIIO::ref(dst), OIIO::cref(src),
                        _1 /*roi*/, 1 /*nthreads*/),
            roi, nthreads);
        return true;
    }

    const ImageSpec &srcspec (src.spec());
    int nc = srcspec.nchannels;

    int alpha_channel, AR_channel, AG_channel, AB_channel;
    int R_channel, G_channel, B_channel;
    int Z_channel, Zback_channel;
    if (! find_deep_channels (srcspec, alpha_channel,
                              AR_channel, AG_channel, AB_channel,
                              R_channel, G_channel, B_channel,
                              Z_channel, Zback_channel)) {
        dst.error ("No alpha channel could be identified");
        return false;
    }
    ASSERT (alpha_channel >= 0 ||
            (AR_channel >= 0 && AG_channel >= 0 && AB_channel >= 0));
    float *val = ALLOCA (float, nc);
    float &ARval (AR_channel >= 0 ? val[AR_channel] : val[alpha_channel]);
    float &AGval (AG_channel >= 0 ? val[AG_channel] : val[alpha_channel]);
    float &ABval (AB_channel >= 0 ? val[AB_channel] : val[alpha_channel]);

    for (ImageBuf::Iterator<DSTTYPE> r (dst, roi);  !r.done();  ++r) {
        int x = r.x(), y = r.y(), z = r.z();
        int samps = src.deep_samples (x, y, z);
        // Clear accumulated values for this pixel (0 for colors, big for Z)
        memset (val, 0, nc*sizeof(float));
        if (Z_channel >= 0 && samps == 0)
            val[Z_channel] = 1.0e30;
        if (Zback_channel >= 0 && samps == 0)
            val[Zback_channel] = 1.0e30;
        for (int s = 0;  s < samps;  ++s) {
            float AR = ARval, AG = AGval, AB = ABval;  // make copies
            float alpha = (AR + AG + AB) / 3.0f;
            if (alpha >= 1.0f)
                break;
            for (int c = 0;  c < nc;  ++c) {
                float v = src.deep_value (x, y, z, c, s);
                if (c == Z_channel || c == Zback_channel)
                    val[c] *= alpha;  // because Z are not premultiplied
                float a;
                if (c == R_channel)
                    a = AR;
                else if (c == G_channel)
                    a = AG;
                else if (c == B_channel)
                    a = AB;
                else
                    a = alpha;
                val[c] += (1.0f - a) * v;
            }
        }

        for (int c = roi.chbegin;  c < roi.chend;  ++c)
            r[c] = val[c];
    }

    return true;
}

bool
ImageBufAlgo::flatten (ImageBuf &dst, const ImageBuf &src,
                       ROI roi, int nthreads)
{
    if (! src.deep()) {
        // For some reason, we were asked to flatten an already-flat image.
        // So just copy it.
        return dst.copy (src);
    }

    // Construct an ideal spec for dst, which is like src but not deep.
    ImageSpec force_spec = src.spec();
    force_spec.deep = false;
    force_spec.channelformats.clear();

    if (! IBAprep (roi, &dst, &src, NULL, &force_spec, IBAprep_SUPPORT_DEEP))
        return false;
    if (dst.spec().deep) {
        dst.error ("Cannot flatten to a deep image");
        return false;
    }

    const ImageSpec &srcspec (src.spec());
    int alpha_channel, AR_channel, AG_channel, AB_channel;
    int R_channel, G_channel, B_channel, Z_channel, Zback_channel;
    if (! find_deep_channels (srcspec, alpha_channel,
                              AR_channel, AG_channel, AB_channel,
                              R_channel, G_channel, B_channel,
                              Z_channel, Zback_channel)) {
        dst.error ("No alpha channel could be identified");
        return false;
    }

    bool ok;
    OIIO_DISPATCH_TYPES (ok, "flatten", flatten_, dst.spec().format,
                         dst, src, roi, nthreads);
    return ok;
}

bool
ImageBufAlgo::deepen (ImageBuf &dst, const ImageBuf &src, float zvalue,
                      ROI roi, int nthreads)
{
    if (src.deep()) {
        // For some reason, we were asked to deepen an already-deep image.
        // So just copy it.
        return dst.copy (src);
        // FIXME: once paste works for deep files, this should really be
        // return paste (dst, roi.xbegin, roi.ybegin, roi.zbegin, roi.chbegin,
        //               src, roi, nthreads);
    }

    // Construct an ideal spec for dst, which is like src but deep.
    const ImageSpec &srcspec (src.spec());
    int nc = srcspec.nchannels;
    int zback_channel = -1;
    ImageSpec force_spec = srcspec;
    force_spec.deep = true;
    force_spec.set_format (TypeDesc::FLOAT);
    force_spec.channelformats.clear();
    for (int c = 0; c < nc; ++c) {
        if (force_spec.channelnames[c] == "Z")
            force_spec.z_channel = c;
        else if (force_spec.channelnames[c] == "Zback")
            zback_channel = c;
    }
    bool add_z_channel = (force_spec.z_channel < 0);
    if (add_z_channel) {
        // No z channel? Make one.
        force_spec.z_channel = force_spec.nchannels++;
        force_spec.channelnames.push_back ("Z");
    }

    if (! IBAprep (roi, &dst, &src, NULL, &force_spec, IBAprep_SUPPORT_DEEP))
        return false;
    if (! dst.deep()) {
        dst.error ("Cannot deepen to a flat image");
        return false;
    }

    float *pixel = OIIO_ALLOCA (float, nc);

    // First, figure out which pixels get a sample and which do not
    for (int z = roi.zbegin; z < roi.zend; ++z)
    for (int y = roi.ybegin; y < roi.yend; ++y)
    for (int x = roi.xbegin; x < roi.xend; ++x) {
        bool has_sample = false;
        src.getpixel (x, y, z, pixel);
        for (int c = 0; c < nc; ++c)
            if (c != force_spec.z_channel && c != zback_channel
                  && pixel[c] != 0.0f) {
                has_sample = true;
                break;
            }
        if (! has_sample && ! add_z_channel)
            for (int c = 0; c < nc; ++c)
                if ((c == force_spec.z_channel || c == zback_channel)
                    && (pixel[c] != 0.0f && pixel[c] < 1e30)) {
                    has_sample = true;
                    break;
                }
        if (has_sample)
            dst.set_deep_samples (x, y, z, 1);
    }

    dst.deep_alloc ();

    // Now actually set the values
    for (int z = roi.zbegin; z < roi.zend; ++z)
    for (int y = roi.ybegin; y < roi.yend; ++y)
    for (int x = roi.xbegin; x < roi.xend; ++x) {
        if (dst.deep_samples (x, y, z) == 0)
            continue;
        for (int c = 0; c < nc; ++c)
            dst.set_deep_value (x, y, z, c, 0 /*sample*/,
                                src.getchannel (x, y, z, c));
        if (add_z_channel)
            dst.set_deep_value (x, y, z, nc, 0, zvalue);
    }

    bool ok = true;
    // FIXME -- the above doesn't split into threads. Someday, it should
    // be refactored like this:
    // OIIO_DISPATCH_COMMON_TYPES2 (ok, "deepen", deepen_,
    //                              dst.spec().format, srcspec.format,
    //                              dst, src, add_z_channel, z, roi, nthreads);
    return ok;
}

OIIO_NAMESPACE_END
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <pthread.h>
#include <memory.h>
#include <iostream>
#include "util/thread.h"
#include "util/exception.h"

#if !defined(LEAN_USE_SPLIT_STACK)

#if defined(LEAN_WINDOWS)
    // no extra included needed so far
#elif defined(__APPLE__)
    #include <sys/resource.h> // NOLINT
#else
    #include <sys/time.h> // NOLINT
    #include <sys/resource.h> // NOLINT
#endif

#define LEAN_MIN_STACK_SPACE 128*1024  // 128 Kb

namespace lean {
void throw_get_stack_size_failed() {
    throw exception("failed to retrieve thread stack size");
}

#if defined(LEAN_WINDOWS)
size_t get_stack_size(int ) {
    return LEAN_WIN_STACK_SIZE;
}
#elif defined (__APPLE__)
size_t get_stack_size(int main) {
    if (main) {
        // Retrieve stack size of the main thread.
        struct rlimit curr;
        if (getrlimit(RLIMIT_STACK, &curr) != 0) {
            throw_get_stack_size_failed();
        }
        return curr.rlim_max;
    } else {
        #if defined(LEAN_MULTI_THREAD)
        // This branch retrieves the default thread size for pthread threads.
        // This is *not* the stack size of the main thread.
        pthread_attr_t attr;
        memset (&attr, 0, sizeof(attr));
        pthread_attr_init(&attr);
        size_t result;
        if (pthread_attr_getstacksize(&attr, &result) != 0) {
            throw_get_stack_size_failed();
        }
        return result;
        #else
        return 0;
        #endif
    }
}
#else
size_t get_stack_size(int main) {
    if (main) {
        // Retrieve stack size of the main thread.
        struct rlimit curr;
        if (getrlimit(RLIMIT_STACK, &curr) != 0) {
            throw_get_stack_size_failed();
        }
        return curr.rlim_cur;
    } else {
        #if defined(LEAN_MULTI_THREAD)
        pthread_attr_t attr;
        memset (&attr, 0, sizeof(attr));
        if (pthread_getattr_np(pthread_self(), &attr) != 0) {
            throw_get_stack_size_failed();
        }
        void * ptr;
        size_t result;
        if (pthread_attr_getstack (&attr, &ptr, &result) != 0) {
            throw_get_stack_size_failed();
        }
        if (pthread_attr_destroy(&attr) != 0) {
            throw_get_stack_size_failed();
        }
        return result;
        #else
        return 0;
        #endif
    }
}
#endif

static bool g_stack_info_init = false;
MK_THREAD_LOCAL_GET(size_t, get_g_stack_size, 0);
MK_THREAD_LOCAL_GET(size_t, get_g_stack_base, 0);

void save_stack_info(bool main) {
    g_stack_info_init = true;
    get_g_stack_size() = get_stack_size(main);
    char x;
    get_g_stack_base() = reinterpret_cast<size_t>(&x);
}

size_t get_used_stack_size() {
    char y;
    size_t curr_stack = reinterpret_cast<size_t>(&y);
    return get_g_stack_base() - curr_stack;
}

size_t get_available_stack_size() {
    size_t sz = get_used_stack_size();
    if (sz > get_g_stack_size())
        return 0;
    else
        return get_g_stack_size() - sz;
}

void check_stack(char const * component_name) {
    if (g_stack_info_init && get_used_stack_size() + LEAN_MIN_STACK_SPACE > get_g_stack_size())
        throw stack_space_exception(component_name);
}
}
#endif
<commit_msg>fix(util/stackinfo): on OSX Boost does not seem to be based on pthread library<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <pthread.h>
#include <memory.h>
#include <iostream>
#include "util/thread.h"
#include "util/exception.h"

#if !defined(LEAN_USE_SPLIT_STACK)

#if defined(LEAN_WINDOWS)
    // no extra included needed so far
#elif defined(__APPLE__)
    #include <sys/resource.h> // NOLINT
#else
    #include <sys/time.h> // NOLINT
    #include <sys/resource.h> // NOLINT
#endif

#define LEAN_MIN_STACK_SPACE 128*1024  // 128 Kb

namespace lean {
void throw_get_stack_size_failed() {
    throw exception("failed to retrieve thread stack size");
}

#if defined(LEAN_WINDOWS)
size_t get_stack_size(int ) {
    return LEAN_WIN_STACK_SIZE;
}
#elif defined (__APPLE__)
size_t get_stack_size(int main) {
    if (main) {
        // Retrieve stack size of the main thread.
        struct rlimit curr;
        if (getrlimit(RLIMIT_STACK, &curr) != 0) {
            throw_get_stack_size_failed();
        }
        return curr.rlim_max;
    } else {
        #if defined(LEAN_MULTI_THREAD)
        {
            #if defined(LEAN_USE_BOOST)
            // Boost does seems to be based on pthread on OSX
            return get_thread_attributes().get_stack_size();
            #else
            // This branch retrieves the default thread size for pthread threads.
            // This is *not* the stack size of the main thread.
            pthread_attr_t attr;
            memset (&attr, 0, sizeof(attr));
            pthread_attr_init(&attr);
            size_t result;
            if (pthread_attr_getstacksize(&attr, &result) != 0) {
                throw_get_stack_size_failed();
            }
            return result;
            #endif
        }
        #else
        return 0;
        #endif
    }
}
#else
size_t get_stack_size(int main) {
    if (main) {
        // Retrieve stack size of the main thread.
        struct rlimit curr;
        if (getrlimit(RLIMIT_STACK, &curr) != 0) {
            throw_get_stack_size_failed();
        }
        return curr.rlim_cur;
    } else {
        #if defined(LEAN_MULTI_THREAD)
        pthread_attr_t attr;
        memset (&attr, 0, sizeof(attr));
        if (pthread_getattr_np(pthread_self(), &attr) != 0) {
            throw_get_stack_size_failed();
        }
        void * ptr;
        size_t result;
        if (pthread_attr_getstack (&attr, &ptr, &result) != 0) {
            throw_get_stack_size_failed();
        }
        if (pthread_attr_destroy(&attr) != 0) {
            throw_get_stack_size_failed();
        }
        return result;
        #else
        return 0;
        #endif
    }
}
#endif

static bool g_stack_info_init = false;
MK_THREAD_LOCAL_GET(size_t, get_g_stack_size, 0);
MK_THREAD_LOCAL_GET(size_t, get_g_stack_base, 0);

void save_stack_info(bool main) {
    g_stack_info_init = true;
    get_g_stack_size() = get_stack_size(main);
    char x;
    get_g_stack_base() = reinterpret_cast<size_t>(&x);
}

size_t get_used_stack_size() {
    char y;
    size_t curr_stack = reinterpret_cast<size_t>(&y);
    return get_g_stack_base() - curr_stack;
}

size_t get_available_stack_size() {
    size_t sz = get_used_stack_size();
    if (sz > get_g_stack_size())
        return 0;
    else
        return get_g_stack_size() - sz;
}

void check_stack(char const * component_name) {
    if (g_stack_info_init && get_used_stack_size() + LEAN_MIN_STACK_SPACE > get_g_stack_size())
        throw stack_space_exception(component_name);
}
}
#endif
<|endoftext|>