<commit_before>#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include <unistd.h>
using namespace std;

#include "bgzf.h"
#include "grabix.h"

int usage()
{
    cout << "usage: grabix index bgzf_file " << endl;
    cout << "       grabix grab bgzf_file line_start [line_end] " << endl;
    cout << endl;
    cout << "examples:" << endl;
    cout << "       # create a grabix index (big.vcf.gz.gbi)" << endl;
    cout << "       grabix index big.vcf.gz" << endl;
    cout << endl;
    cout << "       # extract the 100th line." << endl;
    cout << "       grabix grab big.vcf.gz 100 [line_end] " << endl;
    cout << endl;
    cout << "       # extract the 100th through the 200th lines." << endl;
    cout << "       grabix grab big.vcf.gz 100 200 " << endl;
    cout << endl;
    cout << "       # extract the 100 random lines." << endl;
    cout << "       grabix random big.vcf.gz 100" << endl;
    cout << endl;
    cout << "       # Is the file bgzipped?" << endl;
    cout << "       grabix check big.vcf.gz" << endl;
    cout << endl;
    cout << "       # get total number of lines in the file (minus the header)." << endl;
    cout << "       grabix size big.vcf.gz" << endl;
    cout << "version: " << VERSION << "\n";
    cout << endl;
    return EXIT_SUCCESS;
}

bool bgzf_getline_counting(BGZF * stream)
{
    int c = -1;
    while (true)
    {
        c = bgzf_getc (stream);
        if (c == -1)
            return true;
        else if (c == 10) // \n
            return false;
    }
}

/*
Create a gbi index for the file to facilitate
random access via the BGZF seek utility
*/
int create_grabix_index(string bgzf_file)
{
    if (!bgzf_is_bgzf(bgzf_file.c_str()))
    {
        cerr << "[grabix] " << bgzf_file << " doesn't exist or wasn't compressed with bgzip" << endl;
        exit (1);
    }

    BGZF *bgzf_fp = bgzf_open(bgzf_file.c_str(), "r");
    if (bgzf_fp == NULL)
    {
        cerr << "[grabix] could not open file: " << bgzf_file << endl;
        exit (1);
    }

    // create an index for writing
    string index_file_name = bgzf_file + ".gbi";
    ofstream index_file(index_file_name.c_str(), ios::out);

    // add the offset for the end of the header to the index

    int status;
    kstring_t *line = new kstring_t;
    line->s = '\0';
    line->l = 0;
    line->m = 0;

    int64_t prev_offset = 0;
    int64_t offset = 0;
    while ((status = bgzf_getline(bgzf_fp, '\n', line)) >= 0)
    {
        offset = bgzf_tell (bgzf_fp);
        if (line->s[0] != '#')
            break;
        prev_offset = offset;
    }
    index_file << prev_offset << endl;

    // add the offsets for each CHUNK_SIZE
    // set of records to the index
    size_t chunk_count = 0;
    int64_t total_lines = 1;
    vector<int64_t> chunk_positions;
    chunk_positions.push_back (prev_offset);
    int eof = 1;
    while (true)
    {
        // grab the next line and store the offset
        eof = bgzf_getline(bgzf_fp, '\n', line);
        offset = bgzf_tell (bgzf_fp);
        chunk_count++;
        // stop if we have encountered an empty line
        if (eof <= 0)
        {
            if (bgzf_check_EOF(bgzf_fp) == 1) {
                if (offset > prev_offset) {
                    total_lines++;
                    prev_offset = offset;
                }
                break;
            }
            //break;
        }
        // store the offset of this chunk start
        else if (chunk_count == CHUNK_SIZE)
        {
            chunk_positions.push_back(prev_offset);
            chunk_count = 0;
        }
        total_lines++;
        prev_offset = offset;
    }
    chunk_positions.push_back (prev_offset);
    bgzf_close(bgzf_fp);

    index_file << total_lines << endl;
    for (size_t i = 0; i < chunk_positions.size(); ++i)
    {
        index_file << chunk_positions[i] << endl;
    }
    index_file.close();

    return EXIT_SUCCESS;
}

/*
Load an existing gbi index for the file to facilitate
random access via the BGZF seek utility
*/
void load_index(string bgzf_file, index_info &index)
{
    string index_file_name = bgzf_file + ".gbi";
    // open the index file for reading
    ifstream index_file(index_file_name.c_str(), ios::in);

    if ( !index_file ) {
        cerr << "[grabix] could not find index file: " << index_file_name << ". Exiting!" << endl;
        exit (1);
    }
    else {
        string line;
        getline (index_file, line);
        index.header_end = atol(line.c_str());

        getline (index_file, line);
        index.num_lines = atol(line.c_str());

        while (index_file >> line)
        {
            index.chunk_offsets.push_back(atol(line.c_str()));
        }
    }
    index_file.close();
}

/*
Extract lines [FROM, TO] from file.
*/
int grab(string bgzf_file, int64_t from_line, int64_t to_line)
{
    // load index into vector of offsets
    index_info index;
    load_index(bgzf_file, index);

    if (((int) from_line > index.num_lines)
        ||
        ((int) to_line > index.num_lines))
    {
        cerr << "[grabix] requested lines exceed the number of lines in the file." << endl;
        exit(1);
    }
    else if (from_line < 0)
    {
        cerr << "[grabix] indexes must be positive numbers." << endl;
        exit(1);
    }
    else if (from_line > to_line)
    {
        cerr << "[grabix] requested end line is less than the requested begin line." << endl;
        exit(1);
    }
    else {

        // load the BGZF file
        BGZF *bgzf_fp = bgzf_open(bgzf_file.c_str(), "r");
        if (bgzf_fp == NULL)
        {
            cerr << "[grabix] could not open file: " << bgzf_file << endl;
            exit (1);
        }

        // dump the header if there is one
        int status;
        kstring_t *line = new kstring_t;
        line->s = '\0';
        line->l = 0;
        line->m = 0;

        while ((status = bgzf_getline(bgzf_fp, '\n', line)) != 0)
        {
            if (line->s[0] == '#')
                printf("%s\n", line->s);
            else break;
        }

        // easier to work in 0-based space
        int64_t from_line_0  = from_line - 1;
        // get the chunk index for the requested line
        int64_t requested_chunk = from_line_0 / CHUNK_SIZE;
        // derive the first line in that chunk
        int64_t chunk_line_start = (requested_chunk * CHUNK_SIZE);

        // jump to the correct offset for the relevant chunk
        // and fast forward until we find the requested line
        bgzf_seek (bgzf_fp, index.chunk_offsets[requested_chunk], SEEK_SET);
        while (chunk_line_start <= from_line_0)
        {
            status = bgzf_getline(bgzf_fp, '\n', line);
            chunk_line_start++;
        }
        // now, print each line until we reach the end of the requested block
        do
        {
            printf("%s\n", line->s);
            status = bgzf_getline(bgzf_fp, '\n', line);
            chunk_line_start++;
        } while (chunk_line_start <= to_line);
    }
    return EXIT_SUCCESS;
}

/*
Extract K random lines from file using reservoir sampling
*/
int random(string bgzf_file, uint64_t K)
{
    // load index into vector of offsets
    index_info index;
    load_index(bgzf_file, index);

    if ((int64_t) K > index.num_lines)
    {
        cerr << "[grabix] warning: requested more lines than in the file." << endl;
        exit(1);
    }
    else {
        // load the BGZF file
        BGZF *bgzf_fp = bgzf_open(bgzf_file.c_str(), "r");
        if (bgzf_fp == NULL)
        {
            cerr << "[grabix] could not open file: " << bgzf_file << endl;
            exit (1);
        }

        // seed our random number generator
        size_t seed = (unsigned)time(0)+(unsigned)getpid();
        srand(seed);

        // reservoir sample
        uint64_t s = 0;
        uint64_t N = 0;
        uint64_t result_size = 0;
        vector<string> sample;
        int status;
        kstring_t *line = new kstring_t;
        line->s = '\0';
        line->l = 0;
        line->m = 0;

        while ((status = bgzf_getline(bgzf_fp, '\n', line)) != 0)
        {
            if (line->s[0] == '#')
                printf("%s\n", line->s);
            else break;
        }

        while ((status = bgzf_getline(bgzf_fp, '\n', line)) != 0)
        {
            N++;

            if (status < 0)
                break;

            if (result_size < K)
            {
                sample.push_back(line->s);
                result_size++;
            }
            else
            {
                s = (int) ((double)rand()/(double)RAND_MAX * N);
                if (s < K)
                    sample[s] = line->s;
            }
        }
        bgzf_close(bgzf_fp);

        // report the sample
        for (size_t i = 0; i < sample.size(); ++i)
            printf("%s\n", sample[i].c_str());

    }
    return EXIT_SUCCESS;
}

/*
Return the total number of records in the index.
*/
int size(string bgzf_file)
{
  index_info index;
  load_index(bgzf_file, index);

  return index.num_lines;
}
<commit_msg>indexing: use .gbi.tmp and then rename to .gbi<commit_after>#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <vector>
#include <unistd.h>
using namespace std;

#include "bgzf.h"
#include "grabix.h"

int usage()
{
    cout << "usage: grabix index bgzf_file " << endl;
    cout << "       grabix grab bgzf_file line_start [line_end] " << endl;
    cout << endl;
    cout << "examples:" << endl;
    cout << "       # create a grabix index (big.vcf.gz.gbi)" << endl;
    cout << "       grabix index big.vcf.gz" << endl;
    cout << endl;
    cout << "       # extract the 100th line." << endl;
    cout << "       grabix grab big.vcf.gz 100 [line_end] " << endl;
    cout << endl;
    cout << "       # extract the 100th through the 200th lines." << endl;
    cout << "       grabix grab big.vcf.gz 100 200 " << endl;
    cout << endl;
    cout << "       # extract the 100 random lines." << endl;
    cout << "       grabix random big.vcf.gz 100" << endl;
    cout << endl;
    cout << "       # Is the file bgzipped?" << endl;
    cout << "       grabix check big.vcf.gz" << endl;
    cout << endl;
    cout << "       # get total number of lines in the file (minus the header)." << endl;
    cout << "       grabix size big.vcf.gz" << endl;
    cout << "version: " << VERSION << "\n";
    cout << endl;
    return EXIT_SUCCESS;
}

bool bgzf_getline_counting(BGZF * stream)
{
    int c = -1;
    while (true)
    {
        c = bgzf_getc (stream);
        if (c == -1)
            return true;
        else if (c == 10) // \n
            return false;
    }
}

/*
Create a gbi index for the file to facilitate
random access via the BGZF seek utility
*/
int create_grabix_index(string bgzf_file)
{
    if (!bgzf_is_bgzf(bgzf_file.c_str()))
    {
        cerr << "[grabix] " << bgzf_file << " doesn't exist or wasn't compressed with bgzip" << endl;
        exit (1);
    }

    BGZF *bgzf_fp = bgzf_open(bgzf_file.c_str(), "r");
    if (bgzf_fp == NULL)
    {
        cerr << "[grabix] could not open file: " << bgzf_file << endl;
        exit (1);
    }

    // create an index for writing
    string index_file_name = bgzf_file + ".gbi.tmp";
    ofstream index_file(index_file_name.c_str(), ios::out);

    // add the offset for the end of the header to the index

    int status;
    kstring_t *line = new kstring_t;
    line->s = '\0';
    line->l = 0;
    line->m = 0;

    int64_t prev_offset = 0;
    int64_t offset = 0;
    while ((status = bgzf_getline(bgzf_fp, '\n', line)) >= 0)
    {
        offset = bgzf_tell (bgzf_fp);
        if (line->s[0] != '#')
            break;
        prev_offset = offset;
    }
    index_file << prev_offset << endl;

    // add the offsets for each CHUNK_SIZE
    // set of records to the index
    size_t chunk_count = 0;
    int64_t total_lines = 1;
    vector<int64_t> chunk_positions;
    chunk_positions.push_back (prev_offset);
    int eof = 1;
    while (true)
    {
        // grab the next line and store the offset
        eof = bgzf_getline(bgzf_fp, '\n', line);
        offset = bgzf_tell (bgzf_fp);
        chunk_count++;
        // stop if we have encountered an empty line
        if (eof <= 0)
        {
            if (bgzf_check_EOF(bgzf_fp) == 1) {
                if (offset > prev_offset) {
                    total_lines++;
                    prev_offset = offset;
                }
                break;
            }
            //break;
        }
        // store the offset of this chunk start
        else if (chunk_count == CHUNK_SIZE)
        {
            chunk_positions.push_back(prev_offset);
            chunk_count = 0;
        }
        total_lines++;
        prev_offset = offset;
    }
    chunk_positions.push_back (prev_offset);
    bgzf_close(bgzf_fp);

    index_file << total_lines << endl;
    for (size_t i = 0; i < chunk_positions.size(); ++i)
    {
        index_file << chunk_positions[i] << endl;
    }
    index_file.close();

    return std::rename((bgzf_file + ".gbi.tmp").c_str(), (bgzf_file + ".gbi").c_str());
}

/*
Load an existing gbi index for the file to facilitate
random access via the BGZF seek utility
*/
void load_index(string bgzf_file, index_info &index)
{
    string index_file_name = bgzf_file + ".gbi";
    // open the index file for reading
    ifstream index_file(index_file_name.c_str(), ios::in);

    if ( !index_file ) {
        cerr << "[grabix] could not find index file: " << index_file_name << ". Exiting!" << endl;
        exit (1);
    }
    else {
        string line;
        getline (index_file, line);
        index.header_end = atol(line.c_str());

        getline (index_file, line);
        index.num_lines = atol(line.c_str());

        while (index_file >> line)
        {
            index.chunk_offsets.push_back(atol(line.c_str()));
        }
    }
    index_file.close();
}

/*
Extract lines [FROM, TO] from file.
*/
int grab(string bgzf_file, int64_t from_line, int64_t to_line)
{
    // load index into vector of offsets
    index_info index;
    load_index(bgzf_file, index);

    if (((int) from_line > index.num_lines)
        ||
        ((int) to_line > index.num_lines))
    {
        cerr << "[grabix] requested lines exceed the number of lines in the file." << endl;
        exit(1);
    }
    else if (from_line < 0)
    {
        cerr << "[grabix] indexes must be positive numbers." << endl;
        exit(1);
    }
    else if (from_line > to_line)
    {
        cerr << "[grabix] requested end line is less than the requested begin line." << endl;
        exit(1);
    }
    else {

        // load the BGZF file
        BGZF *bgzf_fp = bgzf_open(bgzf_file.c_str(), "r");
        if (bgzf_fp == NULL)
        {
            cerr << "[grabix] could not open file: " << bgzf_file << endl;
            exit (1);
        }

        // dump the header if there is one
        int status;
        kstring_t *line = new kstring_t;
        line->s = '\0';
        line->l = 0;
        line->m = 0;

        while ((status = bgzf_getline(bgzf_fp, '\n', line)) != 0)
        {
            if (line->s[0] == '#')
                printf("%s\n", line->s);
            else break;
        }

        // easier to work in 0-based space
        int64_t from_line_0  = from_line - 1;
        // get the chunk index for the requested line
        int64_t requested_chunk = from_line_0 / CHUNK_SIZE;
        // derive the first line in that chunk
        int64_t chunk_line_start = (requested_chunk * CHUNK_SIZE);

        // jump to the correct offset for the relevant chunk
        // and fast forward until we find the requested line
        bgzf_seek (bgzf_fp, index.chunk_offsets[requested_chunk], SEEK_SET);
        while (chunk_line_start <= from_line_0)
        {
            status = bgzf_getline(bgzf_fp, '\n', line);
            chunk_line_start++;
        }
        // now, print each line until we reach the end of the requested block
        do
        {
            printf("%s\n", line->s);
            status = bgzf_getline(bgzf_fp, '\n', line);
            chunk_line_start++;
        } while (chunk_line_start <= to_line);
    }
    return EXIT_SUCCESS;
}

/*
Extract K random lines from file using reservoir sampling
*/
int random(string bgzf_file, uint64_t K)
{
    // load index into vector of offsets
    index_info index;
    load_index(bgzf_file, index);

    if ((int64_t) K > index.num_lines)
    {
        cerr << "[grabix] warning: requested more lines than in the file." << endl;
        exit(1);
    }
    else {
        // load the BGZF file
        BGZF *bgzf_fp = bgzf_open(bgzf_file.c_str(), "r");
        if (bgzf_fp == NULL)
        {
            cerr << "[grabix] could not open file: " << bgzf_file << endl;
            exit (1);
        }

        // seed our random number generator
        size_t seed = (unsigned)time(0)+(unsigned)getpid();
        srand(seed);

        // reservoir sample
        uint64_t s = 0;
        uint64_t N = 0;
        uint64_t result_size = 0;
        vector<string> sample;
        int status;
        kstring_t *line = new kstring_t;
        line->s = '\0';
        line->l = 0;
        line->m = 0;

        while ((status = bgzf_getline(bgzf_fp, '\n', line)) != 0)
        {
            if (line->s[0] == '#')
                printf("%s\n", line->s);
            else break;
        }

        while ((status = bgzf_getline(bgzf_fp, '\n', line)) != 0)
        {
            N++;

            if (status < 0)
                break;

            if (result_size < K)
            {
                sample.push_back(line->s);
                result_size++;
            }
            else
            {
                s = (int) ((double)rand()/(double)RAND_MAX * N);
                if (s < K)
                    sample[s] = line->s;
            }
        }
        bgzf_close(bgzf_fp);

        // report the sample
        for (size_t i = 0; i < sample.size(); ++i)
            printf("%s\n", sample[i].c_str());

    }
    return EXIT_SUCCESS;
}

/*
Return the total number of records in the index.
*/
int size(string bgzf_file)
{
  index_info index;
  load_index(bgzf_file, index);

  return index.num_lines;
}
<|endoftext|>


<commit_before>/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
 * Copyright 2015 University of Szeged.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ecma-alloc.h"
#include "ecma-builtins.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-objects.h"
#include "ecma-string-object.h"
#include "ecma-try-catch-macro.h"
#include "jrt.h"

#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_NUMBER_BUILTIN

#define ECMA_BUILTINS_INTERNAL
#include "ecma-builtins-internal.h"

#define BUILTIN_INC_HEADER_NAME "ecma-builtin-number-prototype.inc.h"
#define BUILTIN_UNDERSCORED_ID number_prototype
#include "ecma-builtin-internal-routines-template.inc.h"

/** \addtogroup ecma ECMA
 * @{
 *
 * \addtogroup ecmabuiltins
 * @{
 *
 * \addtogroup numberprototype ECMA Number.prototype object built-in
 * @{
 */

/**
 * Helper for rounding numbers
 *
 * @return rounded number
 */
static uint64_t
ecma_builtin_number_prototype_helper_round (uint64_t digits, /**< actual number **/
                                            int32_t round_num) /**< number of digits to round off **/
{
  int8_t digit = 0;

  /* Remove unneeded precision digits. */
  while (round_num > 0)
  {
    digit = (int8_t) (digits % 10);
    digits /= 10;
    round_num--;
  }

  /* Round the last digit up if neccessary */
  if (digit >= 5)
  {
    digits++;
  }

  return digits;
} /* ecma_builtin_number_prototype_helper_round */

/**
 * The Number.prototype object's 'toString' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.2
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_string (ecma_value_t this_arg, /**< this argument */
                                                const ecma_value_t* arguments_list_p, /**< arguments list */
                                                ecma_length_t arguments_list_len) /**< number of arguments */
{
  ecma_number_t this_arg_number;

  if (ecma_is_value_number (this_arg))
  {
    ecma_number_t *this_arg_number_p = ecma_get_number_from_value (this_arg);

    this_arg_number = *this_arg_number_p;
  }
  else if (ecma_is_value_object (this_arg))
  {
    ecma_object_t *obj_p = ecma_get_object_from_value (this_arg);

    if (ecma_object_get_class_name (obj_p) == ECMA_MAGIC_STRING_NUMBER_UL)
    {
      ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p,
                                                                       ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE);

      ecma_number_t *prim_value_num_p = ECMA_GET_NON_NULL_POINTER (ecma_number_t,
                                                                   prim_value_prop_p->u.internal_property.value);
      this_arg_number = *prim_value_num_p;
    }
    else
    {
      return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
    }
  }
  else
  {
    return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
  }

  if (arguments_list_len == 0)
  {
    ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number);

    return ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p));
  }
  {
    ECMA_BUILTIN_CP_UNIMPLEMENTED (arguments_list_p);
  }
} /* ecma_builtin_number_prototype_object_to_string */

/**
 * The Number.prototype object's 'toLocaleString' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.3
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_locale_string (ecma_value_t this_arg) /**< this argument */
{
  return ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0);
} /* ecma_builtin_number_prototype_object_to_locale_string */

/**
 * The Number.prototype object's 'valueOf' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.4
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_value_of (ecma_value_t this_arg) /**< this argument */
{
  if (ecma_is_value_number (this_arg))
  {
    return ecma_make_normal_completion_value (ecma_copy_value (this_arg, true));
  }
  else if (ecma_is_value_object (this_arg))
  {
    ecma_object_t *obj_p = ecma_get_object_from_value (this_arg);

    if (ecma_object_get_class_name (obj_p) == ECMA_MAGIC_STRING_NUMBER_UL)
    {
      ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p,
                                                                       ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE);

      ecma_number_t *prim_value_num_p = ECMA_GET_NON_NULL_POINTER (ecma_number_t,
                                                                   prim_value_prop_p->u.internal_property.value);

      ecma_number_t *ret_num_p = ecma_alloc_number ();
      *ret_num_p = *prim_value_num_p;

      return ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
    }
  }

  return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
} /* ecma_builtin_number_prototype_object_value_of */

/**
 * The Number.prototype object's 'toFixed' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.5
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_fixed (ecma_value_t this_arg, /**< this argument */
                                               ecma_value_t arg) /**< routine's argument */
{
  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  ECMA_OP_TO_NUMBER_TRY_CATCH (this_num, this_arg, ret_value);
  ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value);

  /* 1. */
  int32_t frac_digits = ecma_number_to_int32 (arg_num);

  /* 2. */
  if (frac_digits < 0 || frac_digits > 20)
  {
    ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE));
  }
  else
  {
    /* 4. */
    if (ecma_number_is_nan (this_num))
    {
      ecma_string_t *nan_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_NAN);
      ret_value = ecma_make_normal_completion_value (ecma_make_string_value (nan_str_p));
    }
    else
    {
      bool is_negative = false;

      /* 6. */
      if (ecma_number_is_negative (this_num))
      {
        is_negative = true;
        this_num *= -1;
      }

      /* We handle infinities separately. */
      if (ecma_number_is_infinity (this_num))
      {
        ecma_string_t *infinity_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_INFINITY_UL);

        if (is_negative)
        {
          ecma_string_t *neg_str_p = ecma_new_ecma_string ((const ecma_char_t *) "-");
          ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p);
          ecma_deref_ecma_string (infinity_str_p);
          ecma_deref_ecma_string (neg_str_p);
          ret_value = ecma_make_normal_completion_value (ecma_make_string_value (neg_inf_str_p));
        }
        else
        {
          ret_value = ecma_make_normal_completion_value (ecma_make_string_value (infinity_str_p));
        }
      }
      else
      {
        uint64_t digits = 0;
        int32_t num_digits = 0;
        int32_t exponent = 1;

        /* Get the parameters of the number if non-zero. */
        if (!ecma_number_is_zero (this_num))
        {
          ecma_number_to_decimal (this_num, &digits, &num_digits, &exponent);
        }

        digits = ecma_builtin_number_prototype_helper_round (digits, num_digits - exponent - frac_digits);

        /* 7. */
        if (exponent > 21)
        {
          ret_value = ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0);
        }
        /* 8. */
        else
        {
          /* Buffer that is used to construct the string. */
          int buffer_size = (exponent > 0) ? exponent + frac_digits + 1 : frac_digits + 2;
          JERRY_ASSERT (buffer_size > 0);
          MEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, ecma_char_t);

          ecma_char_t* p = buff;

          if (is_negative)
          {
            *p++ = '-';
          }

          int8_t digit = 0;
          uint64_t s = 1;

          /* Calculate the magnitude of the number. This is used to get the digits from left to right. */
          while (s <= digits)
          {
            s *= 10;
          }

          if (exponent <= 0)
          {
            /* Add leading zeros. */
            *p++ = '0';

            if (frac_digits != 0)
            {
              *p++ = '.';
            }

            for (int i = 0; i < -exponent && i < frac_digits; i++)
            {
              *p++ = '0';
            }

            /* Add significant digits. */
            for (int i = -exponent; i < frac_digits; i++)
            {
              digit = 0;
              s /= 10;

              while (digits >= s && s > 0)
              {
                digits -= s;
                digit++;
              }

              *p = (ecma_char_t) ((ecma_char_t) digit + '0');
              p++;
            }
          }
          else
          {
            /* Add significant digits. */
            for (int i = 0; i < exponent; i++)
            {
              digit = 0;
              s /= 10;

              while (digits >= s && s > 0)
              {
                digits -= s;
                digit++;
              }

              *p = (ecma_char_t) ((ecma_char_t) digit + '0');
              p++;
            }

            /* Add the decimal point after whole part. */
            if (frac_digits != 0)
            {
              *p++ = '.';
            }

            /* Add neccessary fracion digits. */
            for (int i = 0; i < frac_digits; i++)
            {
              digit = 0;
              s /= 10;

              while (digits >= s && s > 0)
              {
                digits -= s;
                digit++;
              }

              *p = (ecma_char_t) ((ecma_char_t) digit + '0');
              p++;
            }
          }

          /* String terminator. */
          *p = 0;
          ecma_string_t* str = ecma_new_ecma_string ((ecma_char_t *) buff);

          ret_value = ecma_make_normal_completion_value (ecma_make_string_value (str));
          MEM_FINALIZE_LOCAL_ARRAY (buff);
        }
      }
    }
  }

  ECMA_OP_TO_NUMBER_FINALIZE (arg_num);
  ECMA_OP_TO_NUMBER_FINALIZE (this_num);
  return ret_value;
} /* ecma_builtin_number_prototype_object_to_fixed */

/**
 * The Number.prototype object's 'toExponential' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.6
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_exponential (ecma_value_t this_arg, /**< this argument */
                                                     ecma_value_t arg) /**< routine's argument */
{
  ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
} /* ecma_builtin_number_prototype_object_to_exponential */

/**
 * The Number.prototype object's 'toPrecision' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.7
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_precision (ecma_value_t this_arg, /**< this argument */
                                                   ecma_value_t arg) /**< routine's argument */
{
  ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
} /* ecma_builtin_number_prototype_object_to_precision */

/**
 * @}
 * @}
 * @}
 */

#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_NUMBER_BUILTIN */
<commit_msg>Fix buffer size in Number.prototype.toFixed()<commit_after>/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
 * Copyright 2015 University of Szeged.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ecma-alloc.h"
#include "ecma-builtins.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-objects.h"
#include "ecma-string-object.h"
#include "ecma-try-catch-macro.h"
#include "jrt.h"

#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_NUMBER_BUILTIN

#define ECMA_BUILTINS_INTERNAL
#include "ecma-builtins-internal.h"

#define BUILTIN_INC_HEADER_NAME "ecma-builtin-number-prototype.inc.h"
#define BUILTIN_UNDERSCORED_ID number_prototype
#include "ecma-builtin-internal-routines-template.inc.h"

/** \addtogroup ecma ECMA
 * @{
 *
 * \addtogroup ecmabuiltins
 * @{
 *
 * \addtogroup numberprototype ECMA Number.prototype object built-in
 * @{
 */

/**
 * Helper for rounding numbers
 *
 * @return rounded number
 */
static uint64_t
ecma_builtin_number_prototype_helper_round (uint64_t digits, /**< actual number **/
                                            int32_t round_num) /**< number of digits to round off **/
{
  int8_t digit = 0;

  /* Remove unneeded precision digits. */
  while (round_num > 0)
  {
    digit = (int8_t) (digits % 10);
    digits /= 10;
    round_num--;
  }

  /* Round the last digit up if neccessary */
  if (digit >= 5)
  {
    digits++;
  }

  return digits;
} /* ecma_builtin_number_prototype_helper_round */

/**
 * The Number.prototype object's 'toString' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.2
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_string (ecma_value_t this_arg, /**< this argument */
                                                const ecma_value_t* arguments_list_p, /**< arguments list */
                                                ecma_length_t arguments_list_len) /**< number of arguments */
{
  ecma_number_t this_arg_number;

  if (ecma_is_value_number (this_arg))
  {
    ecma_number_t *this_arg_number_p = ecma_get_number_from_value (this_arg);

    this_arg_number = *this_arg_number_p;
  }
  else if (ecma_is_value_object (this_arg))
  {
    ecma_object_t *obj_p = ecma_get_object_from_value (this_arg);

    if (ecma_object_get_class_name (obj_p) == ECMA_MAGIC_STRING_NUMBER_UL)
    {
      ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p,
                                                                       ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE);

      ecma_number_t *prim_value_num_p = ECMA_GET_NON_NULL_POINTER (ecma_number_t,
                                                                   prim_value_prop_p->u.internal_property.value);
      this_arg_number = *prim_value_num_p;
    }
    else
    {
      return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
    }
  }
  else
  {
    return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
  }

  if (arguments_list_len == 0)
  {
    ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number);

    return ecma_make_normal_completion_value (ecma_make_string_value (ret_str_p));
  }
  {
    ECMA_BUILTIN_CP_UNIMPLEMENTED (arguments_list_p);
  }
} /* ecma_builtin_number_prototype_object_to_string */

/**
 * The Number.prototype object's 'toLocaleString' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.3
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_locale_string (ecma_value_t this_arg) /**< this argument */
{
  return ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0);
} /* ecma_builtin_number_prototype_object_to_locale_string */

/**
 * The Number.prototype object's 'valueOf' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.4
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_value_of (ecma_value_t this_arg) /**< this argument */
{
  if (ecma_is_value_number (this_arg))
  {
    return ecma_make_normal_completion_value (ecma_copy_value (this_arg, true));
  }
  else if (ecma_is_value_object (this_arg))
  {
    ecma_object_t *obj_p = ecma_get_object_from_value (this_arg);

    if (ecma_object_get_class_name (obj_p) == ECMA_MAGIC_STRING_NUMBER_UL)
    {
      ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p,
                                                                       ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE);

      ecma_number_t *prim_value_num_p = ECMA_GET_NON_NULL_POINTER (ecma_number_t,
                                                                   prim_value_prop_p->u.internal_property.value);

      ecma_number_t *ret_num_p = ecma_alloc_number ();
      *ret_num_p = *prim_value_num_p;

      return ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
    }
  }

  return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
} /* ecma_builtin_number_prototype_object_value_of */

/**
 * The Number.prototype object's 'toFixed' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.5
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_fixed (ecma_value_t this_arg, /**< this argument */
                                               ecma_value_t arg) /**< routine's argument */
{
  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  ECMA_OP_TO_NUMBER_TRY_CATCH (this_num, this_arg, ret_value);
  ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value);

  /* 1. */
  int32_t frac_digits = ecma_number_to_int32 (arg_num);

  /* 2. */
  if (frac_digits < 0 || frac_digits > 20)
  {
    ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE));
  }
  else
  {
    /* 4. */
    if (ecma_number_is_nan (this_num))
    {
      ecma_string_t *nan_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_NAN);
      ret_value = ecma_make_normal_completion_value (ecma_make_string_value (nan_str_p));
    }
    else
    {
      bool is_negative = false;

      /* 6. */
      if (ecma_number_is_negative (this_num))
      {
        is_negative = true;
        this_num *= -1;
      }

      /* We handle infinities separately. */
      if (ecma_number_is_infinity (this_num))
      {
        ecma_string_t *infinity_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_INFINITY_UL);

        if (is_negative)
        {
          ecma_string_t *neg_str_p = ecma_new_ecma_string ((const ecma_char_t *) "-");
          ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p);
          ecma_deref_ecma_string (infinity_str_p);
          ecma_deref_ecma_string (neg_str_p);
          ret_value = ecma_make_normal_completion_value (ecma_make_string_value (neg_inf_str_p));
        }
        else
        {
          ret_value = ecma_make_normal_completion_value (ecma_make_string_value (infinity_str_p));
        }
      }
      else
      {
        uint64_t digits = 0;
        int32_t num_digits = 0;
        int32_t exponent = 1;

        /* Get the parameters of the number if non-zero. */
        if (!ecma_number_is_zero (this_num))
        {
          ecma_number_to_decimal (this_num, &digits, &num_digits, &exponent);
        }

        digits = ecma_builtin_number_prototype_helper_round (digits, num_digits - exponent - frac_digits);

        /* 7. */
        if (exponent > 21)
        {
          ret_value = ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0);
        }
        /* 8. */
        else
        {
          /* Buffer that is used to construct the string. */
          int buffer_size = (exponent > 0) ? exponent + frac_digits + 2 : frac_digits + 3;

          if (is_negative)
          {
            buffer_size++;
          }

          JERRY_ASSERT (buffer_size > 0);
          MEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, ecma_char_t);

          ecma_char_t* p = buff;

          if (is_negative)
          {
            *p++ = '-';
          }

          int8_t digit = 0;
          uint64_t s = 1;

          /* Calculate the magnitude of the number. This is used to get the digits from left to right. */
          while (s <= digits)
          {
            s *= 10;
          }

          if (exponent <= 0)
          {
            /* Add leading zeros. */
            *p++ = '0';

            if (frac_digits != 0)
            {
              *p++ = '.';
            }

            for (int i = 0; i < -exponent && i < frac_digits; i++)
            {
              *p++ = '0';
            }

            /* Add significant digits. */
            for (int i = -exponent; i < frac_digits; i++)
            {
              digit = 0;
              s /= 10;

              while (digits >= s && s > 0)
              {
                digits -= s;
                digit++;
              }

              *p = (ecma_char_t) ((ecma_char_t) digit + '0');
              p++;
            }
          }
          else
          {
            /* Add significant digits. */
            for (int i = 0; i < exponent; i++)
            {
              digit = 0;
              s /= 10;

              while (digits >= s && s > 0)
              {
                digits -= s;
                digit++;
              }

              *p = (ecma_char_t) ((ecma_char_t) digit + '0');
              p++;
            }

            /* Add the decimal point after whole part. */
            if (frac_digits != 0)
            {
              *p++ = '.';
            }

            /* Add neccessary fracion digits. */
            for (int i = 0; i < frac_digits; i++)
            {
              digit = 0;
              s /= 10;

              while (digits >= s && s > 0)
              {
                digits -= s;
                digit++;
              }

              *p = (ecma_char_t) ((ecma_char_t) digit + '0');
              p++;
            }
          }

          JERRY_ASSERT (p - buff < buffer_size);
          /* String terminator. */
          *p = 0;
          ecma_string_t* str = ecma_new_ecma_string ((ecma_char_t *) buff);

          ret_value = ecma_make_normal_completion_value (ecma_make_string_value (str));
          MEM_FINALIZE_LOCAL_ARRAY (buff);
        }
      }
    }
  }

  ECMA_OP_TO_NUMBER_FINALIZE (arg_num);
  ECMA_OP_TO_NUMBER_FINALIZE (this_num);
  return ret_value;
} /* ecma_builtin_number_prototype_object_to_fixed */

/**
 * The Number.prototype object's 'toExponential' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.6
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_exponential (ecma_value_t this_arg, /**< this argument */
                                                     ecma_value_t arg) /**< routine's argument */
{
  ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
} /* ecma_builtin_number_prototype_object_to_exponential */

/**
 * The Number.prototype object's 'toPrecision' routine
 *
 * See also:
 *          ECMA-262 v5, 15.7.4.7
 *
 * @return completion value
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_number_prototype_object_to_precision (ecma_value_t this_arg, /**< this argument */
                                                   ecma_value_t arg) /**< routine's argument */
{
  ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
} /* ecma_builtin_number_prototype_object_to_precision */

/**
 * @}
 * @}
 * @}
 */

#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_NUMBER_BUILTIN */
<|endoftext|>


<commit_before>/* A simple server in the internet domain using TCP
   The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <string>
#include <cstring>
#include <pthread.h>			// For multithreading
#include <stdint.h>
#include <typeinfo>

struct thread_info { 	   		/* Used as argument to thread_start() */
	pthread_t 	thread_id;     /* ID returned by pthread_create() */
	int 			sock;			/* Socket. I think */
	// user_type		*users; 		/* Pointer to global users object */
	//session_type	*sessions;		// pointer to global sessions object
	// CryptoPP::SecByteBlock session_key;
	// string 			username;
};

//HashMap of usernames to a tuple of user info or user object containing {username, pin, balance}

void deposit(const std::string* user, unsigned long amount);
void balance(const std::string* user);

void error(const char *msg);

void* consoleThread(void *threadid);
void* socketThread(void* arg);

int main(int argc, char *argv[]) {
  	if (argc != 2) {                     // Test for correct number of arguments
  		std::cerr << "Usage: " << argv[0] << " <Server Port>" << std::endl;
  		exit(1);
  	}
    // socket initialization
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    if (argc < 2) {
        std::cerr << "Usage: ATMserver <Port>" << std::endl;
        exit(1);
    }
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        error("ERROR opening socket");
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    // assign socket to port number
    if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) {
        error("ERROR on binding");
    }
    listen(sockfd,5);
    clilen = sizeof(cli_addr);

    pthread_t thread;
    thread_info args;
    pthread_create(&thread, NULL, consoleThread, &args);

    while (1) {
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0) {
          error("ERROR on accept");
          continue;
        }
        pthread_t thread;
        thread_info args;
        args.sock = newsockfd;

        // pid = fork();
        pthread_create(&thread, NULL, socketThread, &args);
        close(newsockfd);
        // int threadNum* ++;
    } /* end of while */
    close(newsockfd);
    close(sockfd);
  	//create 2 threads, one for I/O another for incomming connections
  	return 0;
}

//
void deposit(const std::string* user, unsigned long amount) {
  std::cout << "dtest" << std::endl;
}

void balance(const std::string* user) {
  std::cout << "btest" << std::endl;
}
void error(const char *msg)
{
    std::cerr << msg <<std::endl;
    exit(1);
}
// Read input until we read a space, then for each character add it to the command string
std::string advanceCommand(const std::string& line, int &index) {
  std::string command = "";
  for(; line[index] != ' ' && index <= line.length(); index++) {
    command += line[index];
  }
  return command;
}
// Skip any number of spaces
void advanceSpaces(const std::string &line, int &index) {
  for(; line[index] == ' ' && index <= line.length(); index++);
}

void *consoleThread(void *threadid) {
	// Read in commands from cin
	for(std::string line; getline(std::cin, line);) {

		int index = 0;
		std::string command = advanceCommand(line, index);
    advanceSpaces(line, index);
		std::string username = advanceCommand(line, index);

		//deposit [username] [amount]  Increase <username>’s balance by <amount>
		if(command.compare("deposit") == 1) {
      advanceSpaces(line, index);
			std::string amount = advanceCommand(line, index);

			// Execute deposit command
			deposit(&username, atol(amount.c_str()));
		}
		//balance [username]  Print the balance of <username>
		else if(command.compare("balance") == 1) {
			// Execute balance command
			balance(&username);
		}
	}
	pthread_exit(NULL);		// Ends the thread
}

void* socketThread(void* args) {
  struct thread_info *tinfo;
  tinfo = (thread_info *) args;
  int sock = tinfo->sock;

  int n;
  char buffer[256];

  bzero(buffer,256);
  n = read(sock,buffer,255);
  if (n < 0) error("ERROR reading from socket");
  printf("Here is the message: %s\n",buffer);
  n = write(sock,"I got your message",18);
  if (n < 0) error("ERROR writing to socket");
	pthread_exit(NULL);		// Ends the thread
  return NULL;
}
<commit_msg>fixed bank socket<commit_after>/* A simple server in the internet domain using TCP
   The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <string>
#include <cstring>
#include <pthread.h>			// For multithreading
#include <stdint.h>
#include <typeinfo>

struct thread_info { 	   		/* Used as argument to thread_start() */
	pthread_t 	thread_id;     /* ID returned by pthread_create() */
	int 			sock;			/* Socket. I think */
	// user_type		*users; 		/* Pointer to global users object */
	//session_type	*sessions;		// pointer to global sessions object
	// CryptoPP::SecByteBlock session_key;
	// string 			username;
};

//HashMap of usernames to a tuple of user info or user object containing {username, pin, balance}

void deposit(const std::string* user, unsigned long amount);
void balance(const std::string* user);

void error(const char *msg);

std::string advanceCommand(const std::string& line, int &index);
void advanceSpaces(const std::string &line, int &index);
void* consoleThread(void *threadid);
void* socketThread(void* arg);

int main(int argc, char *argv[]) {
  	if (argc != 2) {                     // Test for correct number of arguments
  		std::cerr << "Usage: " << argv[0] << " <Server Port>" << std::endl;
  		exit(1);
  	}
    // socket initialization
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    if (argc < 2) {
        std::cerr << "Usage: ATMserver <Port>" << std::endl;
        exit(1);
    }
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        error("ERROR opening socket");
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    // assign socket to port number
    if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) {
        error("ERROR on binding");
    }
    listen(sockfd,5);
    clilen = sizeof(cli_addr);

    pthread_t thread;
    thread_info args;
    pthread_create(&thread, NULL, consoleThread, &args);

    while (1) {
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0) {
          error("ERROR on accept");
          continue;
        }
        pthread_t thread;
        thread_info args;
        args.sock = newsockfd;
        std::cout << "thread" << std::endl;
        pthread_create(&thread, NULL, socketThread, &args);
        // int threadNum* ++;
    } /* end of while */
    close(newsockfd);
    close(sockfd);
  	//create 2 threads, one for I/O another for incomming connections
  	return 0;
}

//
void deposit(const std::string* user, unsigned long amount) {
  std::cout << "dtest" << std::endl;
}

void balance(const std::string* user) {
  std::cout << "btest" << std::endl;
}
void error(const char *msg)
{
    std::cerr << msg <<std::endl;
    exit(1);
}
// Read input until we read a space, then for each character add it to the command string
std::string advanceCommand(const std::string& line, int &index) {
  std::string command = "";
  for(; line[index] != ' ' && index <= line.length(); index++) {
    command += line[index];
  }
  return command;
}
// Skip any number of spaces
void advanceSpaces(const std::string &line, int &index) {
  for(; line[index] == ' ' && index <= line.length(); index++);
}

void* consoleThread(void *threadid) {
	// Read in commands from cin
	for(std::string line; getline(std::cin, line);) {

		int index = 0;
		std::string command = advanceCommand(line, index);
    advanceSpaces(line, index);
		std::string username = advanceCommand(line, index);

		//deposit [username] [amount]  Increase <username>’s balance by <amount>
		if(command.compare("deposit") == 1) {
      advanceSpaces(line, index);
			std::string amount = advanceCommand(line, index);

			// Execute deposit command
			deposit(&username, atol(amount.c_str()));
		}
		//balance [username]  Print the balance of <username>
		else if(command.compare("balance") == 1) {
			// Execute balance command
			balance(&username);
		}
	}
	pthread_exit(NULL);		// Ends the thread
}

void* socketThread(void* args) {
  struct thread_info *tinfo;
  tinfo = (thread_info *) args;
  int sock = tinfo->sock;

  while (1) {
    int n;
    char buffer[256];

    bzero(buffer,256);
    n = read(sock,buffer,255);
    if (n < 0) error("ERROR reading from socket");
    printf("Here is the message: %s\n",buffer);
    n = write(sock,"I got your message",18);
    if (n < 0) error("ERROR writing to socket");
    if (buffer == "exit") {
      std::cout << "exiting!" << std::endl;
	    pthread_exit(NULL);		// Ends the thread
      break;
    }
  }
  return NULL;
}
<|endoftext|>


<commit_before>#include "TreeBuilder.h"
#include <iostream>
#include "JSONDialog.h"
#include "utils.h"
using namespace std;

/*
	1. on Start Object
		push current root to stack
		get current parent
		if(lastKey is not null or parent is array)
			if(parent is not an array)
				get last key
				curRoot = insert into tree (lastKey)
				clear key
			else
				curRoot = insert into tree (counter)
				increment counter
	2. on Start Array
		push current root to stack
		if(currentRoot is not treeRoot)
			get last key
			curRoot = insert into tree (lastKey)
			clear key
	3. on Key
		lastKey = key name
	4. on Value
		get current parent
		if(parent is not an array)
			insert to tree with lastKey:value
			clear key
		else
			insert to tree with counter:value
			increment counter
	5. on End Object
		pop from stack
	6. on End Array
		pop from stack
*/
const char* NULL_STR = "null";
const char* TRUE_STR = "true";
const char* FALSE_STR = "false";

bool TreeBuilder::Null()
{
	return this->String(NULL_STR, static_cast<SizeType>(strlen(NULL_STR)), true);
}

bool TreeBuilder::Bool(bool b)
{
	if (b)
		return this->String(TRUE_STR, static_cast<SizeType>(strlen(TRUE_STR)), true);
	return this->String(FALSE_STR, static_cast<SizeType>(strlen(FALSE_STR)), true);
}

bool TreeBuilder::Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
bool TreeBuilder::Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
bool TreeBuilder::Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
bool TreeBuilder::Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
bool TreeBuilder::Double(double d) { cout << "Double(" << d << ")" << endl; return true; }

bool TreeBuilder::RawNumber(const char *str, SizeType length, bool copy)
{
	return this->String(str, length, copy);
}

bool TreeBuilder::String(const char* str, SizeType length, bool /*copy*/)
{
	// copy and process
	TreeNode *parent = this->stack.top();
	char *value = NULL;
	size_t len = 0;
	if (!parent->isArray)
	{
		len = strlen(this->lastKey) + 3 + length + 1;
		value = new char[len];
		snprintf(value, len, "%s : %s", this->lastKey, str);
		value[len - 1] = '\0';
		delete[] this->lastKey;
		this->lastKey = NULL;
	}
	else
	{
		string strCount = SSTR(parent->counter);
		len = strCount.size() + 3 + length + 1;
		value = new char[len];
		snprintf(value, len, "%s : %s", strCount.c_str(), str);
		value[len - 1] = '\0';
		parent->counter++;
	}

	// insert
	this->dlg->insertToTree(parent->subRoot, value);

	//clear
	delete[] value;
	return true;
}

bool TreeBuilder::StartObject()
{
	TreeNode *parent;
	if (this->stack.empty())
	{
		parent = new TreeNode;
		parent->isArray = false;
		parent->subRoot = treeRoot;
		parent->counter = 0;
		this->stack.push(parent);
	}
	else
	{
		parent = this->stack.top();
	}

	if (this->lastKey != NULL || parent->isArray)
	{
		HTREEITEM newNode;
		if (!parent->isArray)
		{
			newNode = this->dlg->insertToTree(parent->subRoot, this->lastKey);
			delete this->lastKey;
			this->lastKey = NULL;
		}
		else
		{
			newNode = this->dlg->insertToTree(parent->subRoot, SSTR(parent->counter).c_str());
		}

		parent->counter++;
		TreeNode *newTreeNode = new TreeNode;
		newTreeNode->isArray = false;
		newTreeNode->subRoot = newNode;
		newTreeNode->counter = 0;
		this->stack.push(newTreeNode);
	}
	return true;
}

bool TreeBuilder::EndObject(SizeType /*memberCount*/)
{
	if (!this->stack.empty())
	{
		TreeNode *node = this->stack.top();
		this->stack.pop();
		delete node;
	}
	return true;
}

bool TreeBuilder::Key(const char* str, SizeType length, bool /*copy*/)
{
	this->lastKey = new char[length + 1];
	strncpy(this->lastKey, str, length);
	this->lastKey[length] = '\0';
	return true;
}

bool TreeBuilder::StartArray()
{
	TreeNode *parent;
	if (this->stack.empty())
	{
		parent = new TreeNode;
		parent->isArray = true;
		parent->subRoot = treeRoot;
		parent->counter = 0;
		this->stack.push(parent);
		return true;
	}
	else
	{
		parent = this->stack.top();
	}

	if (this->lastKey != NULL || parent->isArray)
	{
		HTREEITEM newNode;
		if (!parent->isArray)
		{
			newNode = this->dlg->insertToTree(parent->subRoot, this->lastKey);
			delete this->lastKey;
			this->lastKey = NULL;
		}
		else
		{
			newNode = this->dlg->insertToTree(parent->subRoot, SSTR(parent->counter).c_str());
		}
		parent->counter++;
		TreeNode *newTreeNode = new TreeNode;
		newTreeNode->isArray = true;
		newTreeNode->subRoot = newNode;
		newTreeNode->counter = 0;
		this->stack.push(newTreeNode);
	}
	return true;
}

bool TreeBuilder::EndArray(SizeType /*elementCount*/)
{
	if (!this->stack.empty())
	{
		TreeNode *node = this->stack.top();
		this->stack.pop();
		delete node;
	}
	return true;
}

<commit_msg>fix crash<commit_after>#include "TreeBuilder.h"
#include <iostream>
#include "JSONDialog.h"
#include "utils.h"
using namespace std;

/*
	1. on Start Object
		push current root to stack
		get current parent
		if(lastKey is not null or parent is array)
			if(parent is not an array)
				get last key
				curRoot = insert into tree (lastKey)
				clear key
			else
				curRoot = insert into tree (counter)
				increment counter
	2. on Start Array
		push current root to stack
		if(currentRoot is not treeRoot)
			get last key
			curRoot = insert into tree (lastKey)
			clear key
	3. on Key
		lastKey = key name
	4. on Value
		get current parent
		if(parent is not an array)
			insert to tree with lastKey:value
			clear key
		else
			insert to tree with counter:value
			increment counter
	5. on End Object
		pop from stack
	6. on End Array
		pop from stack
*/
const char* NULL_STR = "null";
const char* TRUE_STR = "true";
const char* FALSE_STR = "false";

bool TreeBuilder::Null()
{
	return this->String(NULL_STR, static_cast<SizeType>(strlen(NULL_STR)), true);
}

bool TreeBuilder::Bool(bool b)
{
	if (b)
		return this->String(TRUE_STR, static_cast<SizeType>(strlen(TRUE_STR)), true);
	return this->String(FALSE_STR, static_cast<SizeType>(strlen(FALSE_STR)), true);
}

bool TreeBuilder::Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
bool TreeBuilder::Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
bool TreeBuilder::Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
bool TreeBuilder::Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
bool TreeBuilder::Double(double d) { cout << "Double(" << d << ")" << endl; return true; }

bool TreeBuilder::RawNumber(const char *str, SizeType length, bool copy)
{
	return this->String(str, length, copy);
}

bool TreeBuilder::String(const char* str, SizeType length, bool /*copy*/)
{
  // handle case, when there is only a value in input
  char* value = NULL;
  size_t len = 0;
  if (this->stack.empty()) {
    len = length + 1; // 1 for null
    value = new char[len];
    snprintf(value, len, "%s", str);
    value[len - 1] = '\0';
    this->dlg->insertToTree(treeRoot, value);
  }
  else {
    TreeNode* parent = this->stack.top();
    if (!parent->isArray)
    {
      len = strlen(this->lastKey) + 3 + length + 1;
      value = new char[len];
      snprintf(value, len, "%s : %s", this->lastKey, str);
      value[len - 1] = '\0';
      delete[] this->lastKey;
      this->lastKey = NULL;
    }
    else
    {
      string strCount = SSTR(parent->counter);
      len = strCount.size() + 3 + length + 1;
      value = new char[len];
      snprintf(value, len, "%s : %s", strCount.c_str(), str);
      value[len - 1] = '\0';
      parent->counter++;
    }

    // insert
    this->dlg->insertToTree(parent->subRoot, value);
  }
	//clear
	delete[] value;
	return true;
}

bool TreeBuilder::StartObject()
{
	TreeNode *parent;
	if (this->stack.empty())
	{
		parent = new TreeNode;
		parent->isArray = false;
		parent->subRoot = treeRoot;
		parent->counter = 0;
		this->stack.push(parent);
	}
	else
	{
		parent = this->stack.top();
	}

	if (this->lastKey != NULL || parent->isArray)
	{
		HTREEITEM newNode;
		if (!parent->isArray)
		{
			newNode = this->dlg->insertToTree(parent->subRoot, this->lastKey);
			delete this->lastKey;
			this->lastKey = NULL;
		}
		else
		{
			newNode = this->dlg->insertToTree(parent->subRoot, SSTR(parent->counter).c_str());
		}

		parent->counter++;
		TreeNode *newTreeNode = new TreeNode;
		newTreeNode->isArray = false;
		newTreeNode->subRoot = newNode;
		newTreeNode->counter = 0;
		this->stack.push(newTreeNode);
	}
	return true;
}

bool TreeBuilder::EndObject(SizeType /*memberCount*/)
{
	if (!this->stack.empty())
	{
		TreeNode *node = this->stack.top();
		this->stack.pop();
		delete node;
	}
	return true;
}

bool TreeBuilder::Key(const char* str, SizeType length, bool /*copy*/)
{
	this->lastKey = new char[length + 1];
	strncpy(this->lastKey, str, length);
	this->lastKey[length] = '\0';
	return true;
}

bool TreeBuilder::StartArray()
{
	TreeNode *parent;
	if (this->stack.empty())
	{
		parent = new TreeNode;
		parent->isArray = true;
		parent->subRoot = treeRoot;
		parent->counter = 0;
		this->stack.push(parent);
		return true;
	}
	else
	{
		parent = this->stack.top();
	}

	if (this->lastKey != NULL || parent->isArray)
	{
		HTREEITEM newNode;
		if (!parent->isArray)
		{
			newNode = this->dlg->insertToTree(parent->subRoot, this->lastKey);
			delete this->lastKey;
			this->lastKey = NULL;
		}
		else
		{
			newNode = this->dlg->insertToTree(parent->subRoot, SSTR(parent->counter).c_str());
		}
		parent->counter++;
		TreeNode *newTreeNode = new TreeNode;
		newTreeNode->isArray = true;
		newTreeNode->subRoot = newNode;
		newTreeNode->counter = 0;
		this->stack.push(newTreeNode);
	}
	return true;
}

bool TreeBuilder::EndArray(SizeType /*elementCount*/)
{
	if (!this->stack.empty())
	{
		TreeNode *node = this->stack.top();
		this->stack.pop();
		delete node;
	}
	return true;
}

<|endoftext|>


<commit_before>// -*- mode: c++; coding: utf-8 -*-
#pragma once
#ifndef WTL_ALGORITHM_HPP_
#define WTL_ALGORITHM_HPP_

#include <vector>
#include <map>
#include <utility>
#include <algorithm>
#include <stdexcept>

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
namespace wtl {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

template <class V, class U> inline
V subscript(const V& seq, const U& indices) {
    V subset;
    subset.reserve(indices.size());
    for (const auto i: indices) {
        subset.push_back(seq[i]);
    }
    return subset;
}

template <class T> inline
typename std::vector<typename std::remove_pointer<typename T::value_type>::type>
dereference(const T& src) {
    typename std::vector<typename std::remove_pointer<typename T::value_type>::type> dst;
    dst.reserve(src.size());
    for (const auto p: src) {
        dst.push_back(*p);
    }
    return dst;
}

template <class Iter, class Distance> inline
Iter advance_return(Iter i, Distance d) {
    std::advance(i, d); return i;
}

// for vector and deque
template <class V> inline
typename V::iterator sort_unique_erase(V* v) {
    std::sort(begin(*v), end(*v));
    return v->erase(std::unique(begin(*v), end(*v)), end(*v));
}

// ceiling of integer division
template <class T> inline constexpr
T ceil_int_div(T lhs, const T rhs) {
    --lhs /= rhs;
    return ++lhs;
}

// split a sequence into the equally sized pieces
template <class V> inline
std::vector<V> chunk(const V& src, const size_t unit) {
    std::vector<V> dst(ceil_int_div(src.size(), unit));
    size_t i = 0;
    for (auto it=begin(src); it!=end(src); ++it) {
        if (dst[i].size()==unit) {++i;}
        dst[i].push_back(*it);
    }
    return dst;
}

template <class V, class Fn> inline
bool equal(const V& v, const V& u, Fn&& fn) {
    return std::equal(begin(v), end(v), begin(u), fn);
}

template <class V, class Fn> inline
bool equal_matrix(const V& v, const V& u, Fn&& fn) {
    typedef typename V::value_type T;
    return wtl::equal(v, u,
                [&fn](const T& x, const T& y) {
                    return wtl::equal(x, y, fn);
                }
           );
}

// true if signs are the same or both 0
template <class T> struct alike_sign {public:
    constexpr bool operator()(const T& x, const T& y) const {
        return (x * y > T()) || (x == y);
    }
};

// true if std::less(x, y) and signs are different
template <class T> struct less_sign {public:
    constexpr bool operator()(const T& x, const T& y) const {
        return (x < y) && (x * y <= T());
    }
};

template <class T> inline
bool equal_sign(const T& x, const T& y) {
        return wtl::equal(x, y, wtl::alike_sign<typename T::value_type>{});
}

template <class T> inline
bool equal_matrix_sign(const T& x, const T& y) {
    return wtl::equal_matrix(x, y, wtl::alike_sign<typename T::value_type::value_type>{});
}

template <class T> inline
bool lexico_sign(const T& x, const T& y) {
    return std::lexicographical_compare(begin(x), end(x), begin(y), end(y),
                    wtl::less_sign<typename T::value_type>{});
}

template <class T> inline
bool lexico_matrix_sign(const T& x, const T& y) {
    return std::lexicographical_compare(begin(x), end(x), begin(y), end(y),
                    wtl::lexico_sign<typename T::value_type>);
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
// std::map

template <class Key, class Value> inline
std::map<Key, Value>
map(const std::vector<Key>& keys, const std::vector<Value>& values) {
    if (keys.size() != values.size()) {
        throw std::runtime_error("keys.size() != values.size()");
    }
    std::map<Key, Value> output;
    for (size_t i=0; i<keys.size(); ++i) {
        output[keys[i]] = values[i];
    }
    return output;
}

template <size_t I, class T> inline
std::vector<typename std::remove_const<typename std::tuple_element<I, typename T::value_type>::type>::type>
unmap(const T& map_) {
    std::vector<typename std::remove_const<typename std::tuple_element<I, typename T::value_type>::type>::type> output;
    output.reserve(map_.size());
    for (const auto& item: map_) {
        output.push_back(std::get<I>(item));
    }
    return output;
}

template <class T> inline
std::vector<typename std::remove_const<typename std::tuple_element<0, typename T::value_type>::type>::type>
keys(const T& map_) {
    return unmap<0>(map_);
}

template <class T> inline
std::vector<typename std::remove_const<typename std::tuple_element<1, typename T::value_type>::type>::type>
values(const T& map_) {
    return unmap<1>(map_);
}

template <class Map> inline
std::vector<typename Map::mapped_type> expand_counter(const Map& src) {
    std::vector<typename Map::mapped_type> dst;
    dst.reserve(src.size());
    for (const auto& item: src) {
        dst->insert(dst->end(), std::get<1>(item), std::get<0>(item));
    }
    return dst;
}

template <class DstCountMap, class SrcCountMap> inline
void recount(DstCountMap* dst, const SrcCountMap& src) {
    for (const auto& item: src) {
        (*dst)[std::get<0>(item)] += std::get<1>(item);
    }
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

template <class InputIter, class OutputIter, class BinaryOperator> inline
OutputIter pairwise_transform(const InputIter begin_, const InputIter end_, OutputIter result, BinaryOperator op) {
    for (auto it1=begin_; it1!=end_; ++it1) {
        for (auto it2=it1; ++it2!=end_; ++result) {
            *result = op(*it1, *it2);
        }
    }
    return result;
}

template <class Iter, class BinaryOperator> inline
std::vector<typename BinaryOperator::result_type> pairwise_transform(const Iter begin_, const Iter end_, BinaryOperator op) {
    const size_t n = std::distance(begin_, end_);
    const size_t combinations = n * (n - 1) / 2;
    std::vector<typename BinaryOperator::result_type> result(combinations);
    pairwise_transform(begin_, end_, begin(result), op);
    return result;
}

template <class Iter> inline
std::pair<Iter, Iter> nth_pair(const Iter begin_, const Iter end_, const size_t n) {
    size_t i = 0;
    for (auto it1=begin_; it1!=end_; ++it1) {
        for (auto it2=it1; ++it2!=end_; ++i) {
            if (i == n) {return {it1, it2};}
        }
    }
    return {end_, end_};
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
} // namespace wtl
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

#endif /* WTL_ALGORITHM_HPP_ */
<commit_msg>Add rstrip() for vector<commit_after>// -*- mode: c++; coding: utf-8 -*-
#pragma once
#ifndef WTL_ALGORITHM_HPP_
#define WTL_ALGORITHM_HPP_

#include <vector>
#include <map>
#include <utility>
#include <algorithm>
#include <stdexcept>

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
namespace wtl {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

template<class T> inline
void rstrip(std::vector<T>* seq, const T& value=T(0)) {
    auto rit = std::find_if(seq->rbegin(), seq->rend(),
                           [&](const T& x){return x != value;});
    seq->resize(seq->rend() - rit);
}

template<class T> inline
std::vector<T> rstrip(std::vector<T> seq, const T& value=T(0)) {
    rstrip(&seq, value);
    return seq;
}

template <class V, class U> inline
V subscript(const V& seq, const U& indices) {
    V subset;
    subset.reserve(indices.size());
    for (const auto i: indices) {
        subset.push_back(seq[i]);
    }
    return subset;
}

template <class T> inline
typename std::vector<typename std::remove_pointer<typename T::value_type>::type>
dereference(const T& src) {
    typename std::vector<typename std::remove_pointer<typename T::value_type>::type> dst;
    dst.reserve(src.size());
    for (const auto p: src) {
        dst.push_back(*p);
    }
    return dst;
}

template <class Iter, class Distance> inline
Iter advance_return(Iter i, Distance d) {
    std::advance(i, d); return i;
}

// for vector and deque
template <class V> inline
typename V::iterator sort_unique_erase(V* v) {
    std::sort(begin(*v), end(*v));
    return v->erase(std::unique(begin(*v), end(*v)), end(*v));
}

// ceiling of integer division
template <class T> inline constexpr
T ceil_int_div(T lhs, const T rhs) {
    --lhs /= rhs;
    return ++lhs;
}

// split a sequence into the equally sized pieces
template <class V> inline
std::vector<V> chunk(const V& src, const size_t unit) {
    std::vector<V> dst(ceil_int_div(src.size(), unit));
    size_t i = 0;
    for (auto it=begin(src); it!=end(src); ++it) {
        if (dst[i].size()==unit) {++i;}
        dst[i].push_back(*it);
    }
    return dst;
}

template <class V, class Fn> inline
bool equal(const V& v, const V& u, Fn&& fn) {
    return std::equal(begin(v), end(v), begin(u), fn);
}

template <class V, class Fn> inline
bool equal_matrix(const V& v, const V& u, Fn&& fn) {
    typedef typename V::value_type T;
    return wtl::equal(v, u,
                [&fn](const T& x, const T& y) {
                    return wtl::equal(x, y, fn);
                }
           );
}

// true if signs are the same or both 0
template <class T> struct alike_sign {public:
    constexpr bool operator()(const T& x, const T& y) const {
        return (x * y > T()) || (x == y);
    }
};

// true if std::less(x, y) and signs are different
template <class T> struct less_sign {public:
    constexpr bool operator()(const T& x, const T& y) const {
        return (x < y) && (x * y <= T());
    }
};

template <class T> inline
bool equal_sign(const T& x, const T& y) {
        return wtl::equal(x, y, wtl::alike_sign<typename T::value_type>{});
}

template <class T> inline
bool equal_matrix_sign(const T& x, const T& y) {
    return wtl::equal_matrix(x, y, wtl::alike_sign<typename T::value_type::value_type>{});
}

template <class T> inline
bool lexico_sign(const T& x, const T& y) {
    return std::lexicographical_compare(begin(x), end(x), begin(y), end(y),
                    wtl::less_sign<typename T::value_type>{});
}

template <class T> inline
bool lexico_matrix_sign(const T& x, const T& y) {
    return std::lexicographical_compare(begin(x), end(x), begin(y), end(y),
                    wtl::lexico_sign<typename T::value_type>);
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
// std::map

template <class Key, class Value> inline
std::map<Key, Value>
map(const std::vector<Key>& keys, const std::vector<Value>& values) {
    if (keys.size() != values.size()) {
        throw std::runtime_error("keys.size() != values.size()");
    }
    std::map<Key, Value> output;
    for (size_t i=0; i<keys.size(); ++i) {
        output[keys[i]] = values[i];
    }
    return output;
}

template <size_t I, class T> inline
std::vector<typename std::remove_const<typename std::tuple_element<I, typename T::value_type>::type>::type>
unmap(const T& map_) {
    std::vector<typename std::remove_const<typename std::tuple_element<I, typename T::value_type>::type>::type> output;
    output.reserve(map_.size());
    for (const auto& item: map_) {
        output.push_back(std::get<I>(item));
    }
    return output;
}

template <class T> inline
std::vector<typename std::remove_const<typename std::tuple_element<0, typename T::value_type>::type>::type>
keys(const T& map_) {
    return unmap<0>(map_);
}

template <class T> inline
std::vector<typename std::remove_const<typename std::tuple_element<1, typename T::value_type>::type>::type>
values(const T& map_) {
    return unmap<1>(map_);
}

template <class Map> inline
std::vector<typename Map::mapped_type> expand_counter(const Map& src) {
    std::vector<typename Map::mapped_type> dst;
    dst.reserve(src.size());
    for (const auto& item: src) {
        dst->insert(dst->end(), std::get<1>(item), std::get<0>(item));
    }
    return dst;
}

template <class DstCountMap, class SrcCountMap> inline
void recount(DstCountMap* dst, const SrcCountMap& src) {
    for (const auto& item: src) {
        (*dst)[std::get<0>(item)] += std::get<1>(item);
    }
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

template <class InputIter, class OutputIter, class BinaryOperator> inline
OutputIter pairwise_transform(const InputIter begin_, const InputIter end_, OutputIter result, BinaryOperator op) {
    for (auto it1=begin_; it1!=end_; ++it1) {
        for (auto it2=it1; ++it2!=end_; ++result) {
            *result = op(*it1, *it2);
        }
    }
    return result;
}

template <class Iter, class BinaryOperator> inline
std::vector<typename BinaryOperator::result_type> pairwise_transform(const Iter begin_, const Iter end_, BinaryOperator op) {
    const size_t n = std::distance(begin_, end_);
    const size_t combinations = n * (n - 1) / 2;
    std::vector<typename BinaryOperator::result_type> result(combinations);
    pairwise_transform(begin_, end_, begin(result), op);
    return result;
}

template <class Iter> inline
std::pair<Iter, Iter> nth_pair(const Iter begin_, const Iter end_, const size_t n) {
    size_t i = 0;
    for (auto it1=begin_; it1!=end_; ++it1) {
        for (auto it2=it1; ++it2!=end_; ++i) {
            if (i == n) {return {it1, it2};}
        }
    }
    return {end_, end_};
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
} // namespace wtl
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

#endif /* WTL_ALGORITHM_HPP_ */
<|endoftext|>


<commit_before>//
//  AmstradCPC.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 30/07/2017.
//  Copyright © 2017 Thomas Harte. All rights reserved.
//

#include "StaticAnalyser.hpp"

#include "../../Storage/Disk/Parsers/CPM.hpp"
#include "../../Storage/Disk/Encodings/MFM.hpp"

static bool strcmp_insensitive(const char *a, const char *b) {
	if(strlen(a) != strlen(b)) return false;
	while(*a) {
		if(tolower(*a) != towlower(*b)) return false;
		a++;
		b++;
	}
	return true;
}

static std::string RunCommandFor(const Storage::Disk::CPM::File &file) {
	return "run\"" + file.name + "\n";
}

static void InspectDataCatalogue(
	const std::unique_ptr<Storage::Disk::CPM::Catalogue> &data_catalogue,
	StaticAnalyser::Target &target) {
	// If there's just one file, run that.
	if(data_catalogue->files.size() == 1) {
		target.loadingCommand = RunCommandFor(data_catalogue->files[0]);
		return;
	}

	// If only one file is [potentially] BASIC, run that one; otherwise if only one has a suffix
	// that AMSDOS allows to be omitted, pick that one.
	int basic_files = 0;
	int implicit_suffixed_files = 0;

	size_t last_basic_file = 0;
	size_t last_implicit_suffixed_file = 0;

	for(size_t c = 0; c < data_catalogue->files.size(); c++) {
		// Files with nothing but spaces in their name can't be loaded by the user, so disregard them.
		if(data_catalogue->files[c].type == "   " && data_catalogue->files[c].name == "        ")
			continue;

		// Check for whether this is [potentially] BASIC.
		if(data_catalogue->files[c].data.size() >= 128 && !((data_catalogue->files[c].data[18] >> 1) & 7)) {
			basic_files++;
			last_basic_file = c;
		}

		// Check suffix for emptiness.
		if(
			data_catalogue->files[c].type == "   " ||
			strcmp_insensitive(data_catalogue->files[c].type.c_str(), "BAS") ||
			strcmp_insensitive(data_catalogue->files[c].type.c_str(), "BIN")
		) {
			implicit_suffixed_files++;
			last_implicit_suffixed_file = c;
		}
	}
	if(basic_files == 1 || implicit_suffixed_files == 1) {
		size_t selected_file = (basic_files == 1) ? last_basic_file : last_implicit_suffixed_file;
		target.loadingCommand = RunCommandFor(data_catalogue->files[selected_file]);
		return;
	}

	// Desperation.
	target.loadingCommand = "cat\n";
}

static void InspectSystemCatalogue(
	const std::shared_ptr<Storage::Disk::Disk> &disk,
	const std::unique_ptr<Storage::Disk::CPM::Catalogue> &catalogue,
	StaticAnalyser::Target &target) {
	Storage::Encodings::MFM::Parser parser(true, disk);
	// Check that the boot sector exists.
	if(parser.get_sector(0, 0, 0x41) != nullptr) {
		// This is a system disk, then launch it as though it were CP/M.
		target.loadingCommand = "|cpm\n";
	} else {
		InspectDataCatalogue(catalogue, target);
	}
}

void StaticAnalyser::AmstradCPC::AddTargets(
	const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
	const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
	const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
	std::list<StaticAnalyser::Target> &destination) {
	Target target;
	target.machine = Target::AmstradCPC;
	target.probability = 1.0;
	target.disks = disks;
	target.tapes = tapes;
	target.cartridges = cartridges;

	target.amstradcpc.model = AmstradCPCModel::CPC6128;

	if(!target.tapes.empty()) {
		// Ugliness flows here: assume the CPC isn't smart enough to pause between pressing
		// enter and responding to the follow-on prompt to press a key, so just type for
		// a while. Yuck!
		target.loadingCommand = "|tape\nrun\"\n1234567890";
	}

	if(!target.disks.empty()) {
		Storage::Disk::CPM::ParameterBlock data_format;
		data_format.sectors_per_track = 9;
		data_format.tracks = 40;
		data_format.block_size = 1024;
		data_format.first_sector = 0xc1;
		data_format.catalogue_allocation_bitmap = 0xc000;
		data_format.reserved_tracks = 0;

		std::unique_ptr<Storage::Disk::CPM::Catalogue> data_catalogue = Storage::Disk::CPM::GetCatalogue(target.disks.front(), data_format);
		if(data_catalogue) {
			InspectDataCatalogue(data_catalogue, target);
		} else {
			Storage::Disk::CPM::ParameterBlock system_format;
			system_format.sectors_per_track = 9;
			system_format.tracks = 40;
			system_format.block_size = 1024;
			system_format.first_sector = 0x41;
			system_format.catalogue_allocation_bitmap = 0xc000;
			system_format.reserved_tracks = 2;

			std::unique_ptr<Storage::Disk::CPM::Catalogue> system_catalogue = Storage::Disk::CPM::GetCatalogue(target.disks.front(), system_format);
			if(system_catalogue) {
				InspectSystemCatalogue(target.disks.front(), data_catalogue, target);
			}
		}
	}

	destination.push_back(target);
}
<commit_msg>Added an extra test to try to avoid spurious |cpm launches.<commit_after>//
//  AmstradCPC.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 30/07/2017.
//  Copyright © 2017 Thomas Harte. All rights reserved.
//

#include "StaticAnalyser.hpp"

#include "../../Storage/Disk/Parsers/CPM.hpp"
#include "../../Storage/Disk/Encodings/MFM.hpp"

static bool strcmp_insensitive(const char *a, const char *b) {
	if(strlen(a) != strlen(b)) return false;
	while(*a) {
		if(tolower(*a) != towlower(*b)) return false;
		a++;
		b++;
	}
	return true;
}

static std::string RunCommandFor(const Storage::Disk::CPM::File &file) {
	return "run\"" + file.name + "\n";
}

static void InspectDataCatalogue(
	const Storage::Disk::CPM::Catalogue &catalogue,
	StaticAnalyser::Target &target) {
	// If there's just one file, run that.
	if(catalogue.files.size() == 1) {
		target.loadingCommand = RunCommandFor(catalogue.files[0]);
		return;
	}

	// If only one file is [potentially] BASIC, run that one; otherwise if only one has a suffix
	// that AMSDOS allows to be omitted, pick that one.
	int basic_files = 0;
	int implicit_suffixed_files = 0;

	size_t last_basic_file = 0;
	size_t last_implicit_suffixed_file = 0;

	for(size_t c = 0; c < catalogue.files.size(); c++) {
		// Files with nothing but spaces in their name can't be loaded by the user, so disregard them.
		if(catalogue.files[c].type == "   " && catalogue.files[c].name == "        ")
			continue;

		// Check for whether this is [potentially] BASIC.
		if(catalogue.files[c].data.size() >= 128 && !((catalogue.files[c].data[18] >> 1) & 7)) {
			basic_files++;
			last_basic_file = c;
		}

		// Check suffix for emptiness.
		if(
			catalogue.files[c].type == "   " ||
			strcmp_insensitive(catalogue.files[c].type.c_str(), "BAS") ||
			strcmp_insensitive(catalogue.files[c].type.c_str(), "BIN")
		) {
			implicit_suffixed_files++;
			last_implicit_suffixed_file = c;
		}
	}
	if(basic_files == 1 || implicit_suffixed_files == 1) {
		size_t selected_file = (basic_files == 1) ? last_basic_file : last_implicit_suffixed_file;
		target.loadingCommand = RunCommandFor(catalogue.files[selected_file]);
		return;
	}

	// Desperation.
	target.loadingCommand = "cat\n";
}

static void InspectSystemCatalogue(
	const std::shared_ptr<Storage::Disk::Disk> &disk,
	const Storage::Disk::CPM::Catalogue &catalogue,
	StaticAnalyser::Target &target) {
	Storage::Encodings::MFM::Parser parser(true, disk);

	// Check that the boot sector exists and looks like it had content written to it.
	std::shared_ptr<Storage::Encodings::MFM::Sector> boot_sector = parser.get_sector(0, 0, 0x41);
	if(boot_sector != nullptr) {
		// Check that the first 64 bytes of the sector aren't identical; if they are then probably
		// this disk was formatted and the filler byte never replaced.
		bool matched = true;
		for(size_t c = 1; c < 64; c++) {
			if(boot_sector->data[c] != boot_sector->data[0]) {
				matched = false;
				break;
			}
		}

		// This is a system disk, then launch it as though it were CP/M.
		if(!matched) {
			target.loadingCommand = "|cpm\n";
			return;
		}
	}

	InspectDataCatalogue(catalogue, target);
}

void StaticAnalyser::AmstradCPC::AddTargets(
	const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
	const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
	const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
	std::list<StaticAnalyser::Target> &destination) {
	Target target;
	target.machine = Target::AmstradCPC;
	target.probability = 1.0;
	target.disks = disks;
	target.tapes = tapes;
	target.cartridges = cartridges;

	target.amstradcpc.model = AmstradCPCModel::CPC6128;

	if(!target.tapes.empty()) {
		// Ugliness flows here: assume the CPC isn't smart enough to pause between pressing
		// enter and responding to the follow-on prompt to press a key, so just type for
		// a while. Yuck!
		target.loadingCommand = "|tape\nrun\"\n1234567890";
	}

	if(!target.disks.empty()) {
		Storage::Disk::CPM::ParameterBlock data_format;
		data_format.sectors_per_track = 9;
		data_format.tracks = 40;
		data_format.block_size = 1024;
		data_format.first_sector = 0xc1;
		data_format.catalogue_allocation_bitmap = 0xc000;
		data_format.reserved_tracks = 0;

		std::unique_ptr<Storage::Disk::CPM::Catalogue> data_catalogue = Storage::Disk::CPM::GetCatalogue(target.disks.front(), data_format);
		if(data_catalogue) {
			InspectDataCatalogue(*data_catalogue, target);
		} else {
			Storage::Disk::CPM::ParameterBlock system_format;
			system_format.sectors_per_track = 9;
			system_format.tracks = 40;
			system_format.block_size = 1024;
			system_format.first_sector = 0x41;
			system_format.catalogue_allocation_bitmap = 0xc000;
			system_format.reserved_tracks = 2;

			std::unique_ptr<Storage::Disk::CPM::Catalogue> system_catalogue = Storage::Disk::CPM::GetCatalogue(target.disks.front(), system_format);
			if(system_catalogue) {
				InspectSystemCatalogue(target.disks.front(), *system_catalogue, target);
			}
		}
	}

	destination.push_back(target);
}
<|endoftext|>