<commit_before>/*
 * Copyright (c) 2021 The Regents of the University of California.
 * 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 copyright holders 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.
 */

#ifndef __BASE_STATS_UNITS_HH__
#define __BASE_STATS_UNITS_HH__

#include <type_traits>

#include "base/cprintf.hh"

/**
 * Convenience macros to declare the unit of a stat.
 */
#define UNIT_CYCLE Stats::Units::Cycle::get()
#define UNIT_TICK Stats::Units::Tick::get()
#define UNIT_SECOND Stats::Units::Second::get()
#define UNIT_BIT Stats::Units::Bit::get()
#define UNIT_BYTE Stats::Units::Byte::get()
#define UNIT_JOULE Stats::Units::Joule::get()
#define UNIT_VOLT Stats::Units::Volt::get()
#define UNIT_CELSIUS Stats::Units::DegreeCelsius::get()
#define UNIT_RATE(T1, T2) Stats::Units::Rate<T1, T2>::get()
#define UNIT_RATIO Stats::Units::Ratio::get()
#define UNIT_COUNT Stats::Units::Count::get()
#define UNIT_UNSPECIFIED Stats::Units::Unspecified::get()

#define UNIT_WATT UNIT_RATE(Stats::Units::Joule, Stats::Units::Second)

namespace Stats {

/**
 * Units for Stats.
 *
 * This header file provides an ability to associate a stat object with a
 * specific unit.
 *
 * The supported units are:
 *   - Cycle: represents clock cycles.
 *   - Tick: represents the count of gem5's Tick.
 *   - Second: represents the base unit of time defined by SI.
 *   - Bit: represents the number of computer bits.
 *   - Byte: represents 8 bits.
 *   - Volt: a SI derived unit measuring potential difference.
 *   - Joule: represents joule, a unit of energy, as defined by SI.
 *   - Watt: represents 1 watt, where 1 watt = 1 joule / second.
 *   - Celsius: represents 1 Celsius degree as defined by SI.
 *   - Rate(T1, T2): represents the unit of a quantity of T1 divided by
 *                   a quantity of T2.
 *   - Ratio: represents the unit of a quantity of unit T divided by a quantity
 *            of T.
 *   - Count: represents the count of a quantity that is not defined above.
 *   - Unspecified: the unit of the stat is unspecified.
 *
 * Each unit class is intended to be a singleton, which means only each unit
 * class has at most one object of that class exist throughout the program.
 * Therefore, copy constructors and assignment operators are deleted functions.
 *
 * When any of the following criteria is met, a new unit should be added,
 *   - The new unit is significant enough to be not included in Count unit.
 *     (e.g. Cycle unit, Tick unit)
 */
namespace Units {

/**
 * The Base class is the parent class of all unit classes.
 * This class is intended to an abstract class specifying common behaviors of
 * all unit classes.
 */
class Base
{
  public:
    virtual std::string getUnitString() const = 0;
};

class Cycle : public Base
{
  private:
    Cycle() {}
  public:
    Cycle(Cycle const&) = delete;
    void operator=(Cycle const&) = delete;
    static Cycle*
    get()
    {
        static Cycle instance;
        return &instance;
    }
    static std::string toString() { return "Cycle"; }
    std::string getUnitString() const override { return Cycle::toString(); }
};

class Tick : public Base
{
  private:
    Tick() {}
  public:
    Tick(Tick const&) = delete;
    void operator=(Tick const&) = delete;
    static Tick*
    get()
    {
        static Tick instance;
        return &instance;
    }
    static std::string toString() { return "Tick"; }
    std::string getUnitString() const override { return Tick::toString(); }
};

class Second : public Base
{
  private:
    Second() {}
  public:
    Second(Second const&) = delete;
    void operator=(Second const&) = delete;
    static Second*
    get()
    {
        static Second instance;
        return &instance;
    }
    static std::string toString() { return "Second"; }
    std::string getUnitString() const override { return Second::toString(); }
};

class Bit : public Base
{
  private:
    Bit() {}
  public:
    Bit(Bit const&) = delete;
    void operator=(Bit const&) = delete;
    static Bit*
    get()
    {
        static Bit instance;
        return &instance;
    }
    static std::string toString() { return "Bit"; }
    std::string getUnitString() const override { return Bit::toString(); }
};

class Byte : public Base
{
  private:
    Byte() {}
  public:
    Byte(Byte const&) = delete;
    void operator=(Byte const&) = delete;
    static Byte*
    get()
    {
        static Byte instance;
        return &instance;
    }
    static std::string toString() { return "Byte"; }
    std::string getUnitString() const override { return Byte::toString(); }
};

class Watt : public Base
{
  private:
    Watt() {}
  public:
    Watt(Watt const&) = delete;
    void operator=(Watt const&) = delete;
    static Watt*
    get()
    {
        static Watt instance;
        return &instance;
    }
    static std::string toString() { return "Watt"; }
    std::string getUnitString() const override { return Watt::toString(); }
};

class Joule : public Base
{
  private:
    Joule() {}
  public:
    Joule(Joule const&) = delete;
    void operator=(Joule const&) = delete;
    static Joule*
    get()
    {
        static Joule instance;
        return &instance;
    }
    static std::string toString() { return "Joule"; }
    std::string getUnitString() const override { return Joule::toString(); }
};

class Volt : public Base
{
  private:
    Volt() {}
  public:
    Volt(Volt const&) = delete;
    void operator=(Volt const&) = delete;
    static Volt*
    get()
    {
        static Volt instance;
        return &instance;
    }
    static std::string toString() { return "Volt"; }
    std::string getUnitString() const override { return Volt::toString(); }
};

class DegreeCelsius : public Base
{
  private:
    DegreeCelsius() {}
  public:
    DegreeCelsius(DegreeCelsius const&) = delete;
    void operator=(DegreeCelsius const&) = delete;
    static DegreeCelsius*
    get()
    {
        static DegreeCelsius instance;
        return &instance;
    }
    static std::string toString() { return "Celsius"; }
    std::string
    getUnitString() const override
    {
       return DegreeCelsius::toString();
    }
};

class Count : public Base
{
  private:
    Count() {}
  public:
    Count(Count const&) = delete;
    void operator=(Count const&) = delete;
    static Count*
    get()
    {
        static Count instance;
        return &instance;
    }
    static std::string toString() { return "Count"; }
    std::string getUnitString() const override { return Count::toString(); }
};

template <typename T1, typename T2>
class Rate : public Base
{
  static_assert(std::is_base_of<Base, T1>::value,
                "Rate(T1,T2) must have T1 and T2 derived from"
                "Stats::Units::Base");
  static_assert(std::is_base_of<Base, T2>::value,
                "Rate(T1,T2) must have T1 and T2 derived from"
                "Stats::Units::Base");
  private:
    Rate<T1,T2>() {}
  public:
    Rate<T1,T2>(Rate<T1,T2> const&) = delete;
    void operator=(Rate<T1,T2> const&) = delete;
    static Rate<T1,T2>*
    get()
    {
        static Rate<T1,T2> instance;
        return &instance;
    }
    static std::string
    toString()
    {
        return csprintf("(%s/%s)", T1::toString(), T2::toString());
    }
    std::string
    getUnitString() const override
    {
        return Rate<T1,T2>::toString();
    }
};

class Ratio : public Base
{
  private:
    Ratio() {}
  public:
    Ratio(Ratio const&) = delete;
    void operator=(Ratio const&) = delete;
    static Ratio*
    get()
    {
        static Ratio instance;
        return &instance;
    }
    static std::string toString() { return "Ratio"; }
    std::string getUnitString() const override { return Ratio::toString(); }
};

class Unspecified : public Base
{
  private:
    Unspecified() {}
  public:
    Unspecified(Unspecified const&) = delete;
    void operator=(Unspecified const&) = delete;
    static Unspecified*
    get()
    {
        static Unspecified instance;
        return &instance;
    }
    static std::string toString() { return "Unspecified"; }
    std::string
    getUnitString() const override
    {
        return Unspecified::toString();
    }
};

} // namespace Units

} // namespace Stats

#endif // __BASE_STATS_UNITS_HH__
<commit_msg>base-stats: Fix Watt Unit<commit_after>/*
 * Copyright (c) 2021 The Regents of the University of California.
 * 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 copyright holders 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.
 */

#ifndef __BASE_STATS_UNITS_HH__
#define __BASE_STATS_UNITS_HH__

#include <type_traits>

#include "base/cprintf.hh"

/**
 * Convenience macros to declare the unit of a stat.
 */
#define UNIT_CYCLE Stats::Units::Cycle::get()
#define UNIT_TICK Stats::Units::Tick::get()
#define UNIT_SECOND Stats::Units::Second::get()
#define UNIT_BIT Stats::Units::Bit::get()
#define UNIT_BYTE Stats::Units::Byte::get()
#define UNIT_JOULE Stats::Units::Joule::get()
#define UNIT_VOLT Stats::Units::Volt::get()
#define UNIT_CELSIUS Stats::Units::DegreeCelsius::get()
#define UNIT_RATE(T1, T2) Stats::Units::Rate<T1, T2>::get()
#define UNIT_RATIO Stats::Units::Ratio::get()
#define UNIT_COUNT Stats::Units::Count::get()
#define UNIT_WATT Stats::Units::Watt::get()
#define UNIT_UNSPECIFIED Stats::Units::Unspecified::get()

namespace Stats {

/**
 * Units for Stats.
 *
 * This header file provides an ability to associate a stat object with a
 * specific unit.
 *
 * The supported units are:
 *   - Cycle: represents clock cycles.
 *   - Tick: represents the count of gem5's Tick.
 *   - Second: represents the base unit of time defined by SI.
 *   - Bit: represents the number of computer bits.
 *   - Byte: represents 8 bits.
 *   - Volt: a SI derived unit measuring potential difference.
 *   - Joule: represents joule, a unit of energy, as defined by SI.
 *   - Watt: represents 1 watt, where 1 watt = 1 joule / second.
 *   - Celsius: represents 1 Celsius degree as defined by SI.
 *   - Rate(T1, T2): represents the unit of a quantity of T1 divided by
 *                   a quantity of T2.
 *   - Ratio: represents the unit of a quantity of unit T divided by a quantity
 *            of T.
 *   - Count: represents the count of a quantity that is not defined above.
 *   - Unspecified: the unit of the stat is unspecified.
 *
 * Each unit class is intended to be a singleton, which means only each unit
 * class has at most one object of that class exist throughout the program.
 * Therefore, copy constructors and assignment operators are deleted functions.
 *
 * When any of the following criteria is met, a new unit should be added,
 *   - The new unit is significant enough to be not included in Count unit.
 *     (e.g. Cycle unit, Tick unit)
 */
namespace Units {

/**
 * The Base class is the parent class of all unit classes.
 * This class is intended to an abstract class specifying common behaviors of
 * all unit classes.
 */
class Base
{
  public:
    virtual std::string getUnitString() const = 0;
};

class Cycle : public Base
{
  private:
    Cycle() {}
  public:
    Cycle(Cycle const&) = delete;
    void operator=(Cycle const&) = delete;
    static Cycle*
    get()
    {
        static Cycle instance;
        return &instance;
    }
    static std::string toString() { return "Cycle"; }
    std::string getUnitString() const override { return Cycle::toString(); }
};

class Tick : public Base
{
  private:
    Tick() {}
  public:
    Tick(Tick const&) = delete;
    void operator=(Tick const&) = delete;
    static Tick*
    get()
    {
        static Tick instance;
        return &instance;
    }
    static std::string toString() { return "Tick"; }
    std::string getUnitString() const override { return Tick::toString(); }
};

class Second : public Base
{
  private:
    Second() {}
  public:
    Second(Second const&) = delete;
    void operator=(Second const&) = delete;
    static Second*
    get()
    {
        static Second instance;
        return &instance;
    }
    static std::string toString() { return "Second"; }
    std::string getUnitString() const override { return Second::toString(); }
};

class Bit : public Base
{
  private:
    Bit() {}
  public:
    Bit(Bit const&) = delete;
    void operator=(Bit const&) = delete;
    static Bit*
    get()
    {
        static Bit instance;
        return &instance;
    }
    static std::string toString() { return "Bit"; }
    std::string getUnitString() const override { return Bit::toString(); }
};

class Byte : public Base
{
  private:
    Byte() {}
  public:
    Byte(Byte const&) = delete;
    void operator=(Byte const&) = delete;
    static Byte*
    get()
    {
        static Byte instance;
        return &instance;
    }
    static std::string toString() { return "Byte"; }
    std::string getUnitString() const override { return Byte::toString(); }
};

class Watt : public Base
{
  private:
    Watt() {}
  public:
    Watt(Watt const&) = delete;
    void operator=(Watt const&) = delete;
    static Watt*
    get()
    {
        static Watt instance;
        return &instance;
    }
    static std::string toString() { return "Watt"; }
    std::string getUnitString() const override { return Watt::toString(); }
};

class Joule : public Base
{
  private:
    Joule() {}
  public:
    Joule(Joule const&) = delete;
    void operator=(Joule const&) = delete;
    static Joule*
    get()
    {
        static Joule instance;
        return &instance;
    }
    static std::string toString() { return "Joule"; }
    std::string getUnitString() const override { return Joule::toString(); }
};

class Volt : public Base
{
  private:
    Volt() {}
  public:
    Volt(Volt const&) = delete;
    void operator=(Volt const&) = delete;
    static Volt*
    get()
    {
        static Volt instance;
        return &instance;
    }
    static std::string toString() { return "Volt"; }
    std::string getUnitString() const override { return Volt::toString(); }
};

class DegreeCelsius : public Base
{
  private:
    DegreeCelsius() {}
  public:
    DegreeCelsius(DegreeCelsius const&) = delete;
    void operator=(DegreeCelsius const&) = delete;
    static DegreeCelsius*
    get()
    {
        static DegreeCelsius instance;
        return &instance;
    }
    static std::string toString() { return "Celsius"; }
    std::string
    getUnitString() const override
    {
       return DegreeCelsius::toString();
    }
};

class Count : public Base
{
  private:
    Count() {}
  public:
    Count(Count const&) = delete;
    void operator=(Count const&) = delete;
    static Count*
    get()
    {
        static Count instance;
        return &instance;
    }
    static std::string toString() { return "Count"; }
    std::string getUnitString() const override { return Count::toString(); }
};

template <typename T1, typename T2>
class Rate : public Base
{
  static_assert(std::is_base_of<Base, T1>::value,
                "Rate(T1,T2) must have T1 and T2 derived from"
                "Stats::Units::Base");
  static_assert(std::is_base_of<Base, T2>::value,
                "Rate(T1,T2) must have T1 and T2 derived from"
                "Stats::Units::Base");
  private:
    Rate<T1,T2>() {}
  public:
    Rate<T1,T2>(Rate<T1,T2> const&) = delete;
    void operator=(Rate<T1,T2> const&) = delete;
    static Rate<T1,T2>*
    get()
    {
        static Rate<T1,T2> instance;
        return &instance;
    }
    static std::string
    toString()
    {
        return csprintf("(%s/%s)", T1::toString(), T2::toString());
    }
    std::string
    getUnitString() const override
    {
        return Rate<T1,T2>::toString();
    }
};

class Ratio : public Base
{
  private:
    Ratio() {}
  public:
    Ratio(Ratio const&) = delete;
    void operator=(Ratio const&) = delete;
    static Ratio*
    get()
    {
        static Ratio instance;
        return &instance;
    }
    static std::string toString() { return "Ratio"; }
    std::string getUnitString() const override { return Ratio::toString(); }
};

class Unspecified : public Base
{
  private:
    Unspecified() {}
  public:
    Unspecified(Unspecified const&) = delete;
    void operator=(Unspecified const&) = delete;
    static Unspecified*
    get()
    {
        static Unspecified instance;
        return &instance;
    }
    static std::string toString() { return "Unspecified"; }
    std::string
    getUnitString() const override
    {
        return Unspecified::toString();
    }
};

} // namespace Units

} // namespace Stats

#endif // __BASE_STATS_UNITS_HH__
<|endoftext|>


<commit_before>/**
*******************************************************************************
*                                                                             *
* ECU: iRacing MP4-30 Performance Analysis Project                            *
*                                                                             *
*******************************************************************************
* Copyright 2016 Adrian Garcia Cruz. All rights reserved.                     *
* Released under the BSD license. see LICENSE for more information            *
*                                                                             *
* Author: Adrian Garcia Cruz <garcia.adrian.cruz@gmail.com>                   *
*******************************************************************************
*/

#include "loop.h"

#include <irsdk/irsdk_client.h>
#include <irsdk/irsdk_defines.h>
#include <irsdk/yaml_parser.h>
#include "ir_helper.h"
#include <stdlib.h>
#include <Strsafe.h>
#include <io.h>
#include <fcntl.h>
#include <Shlobj.h>

void check_track(sqlite3 *db)
{
  static char buffer[512];
  static char sql[512];
  sqlite3_stmt *sql_stmt = {0};
  int rc = 0;

  char *ir_buffer;

  if (irsdkClient::instance().waitForData(16)) {
    ir_buffer = ir_get_variable("WeekendInfo:TrackDisplayName:", irsdk_getSessionInfoStr());
    sprintf_s(sql, "SELECT * FROM tracks WHERE name='%s'", ir_buffer);

    rc = sqlite3_prepare_v2(db, sql, sizeof(sql), &sql_stmt, NULL);
    handle_sql_rc(rc, sql, db, false, false, true);

    rc = sqlite3_step(sql_stmt);
    DEBUG_OUTA("[STARTUP]: Checking if current track is on the database\n", buffer);

    if (!handle_sql_rc(rc, sql, db, true, true, true)) {

      DEBUG_OUTA("[STARTUP]: Entry for track '%s' was not found in table `tracks`\n"
                 "[STARTUP]: Creating entry in table `tracks` for '%s'\n",
                 buffer, ir_buffer, ir_buffer);
      sprintf_s(sql, "INSERT INTO tracks(name) VALUES('%s')", ir_buffer);

      rc = sqlite3_prepare_v2(db, sql, sizeof(sql), &sql_stmt, NULL);
      handle_sql_rc(rc, sql, db, false, true, false);
      rc = sqlite3_step(sql_stmt);
      handle_sql_rc(rc, sql, db, true, true, false);

    } else {
      DEBUG_OUTA("[STARTUP]: Track %s found in database\n", buffer, ir_buffer);
      const unsigned char *sql_result = sqlite3_column_text(sql_stmt, 1);
    }

    free(ir_buffer);
  }
}

ibt *parse_ibt(intptr_t fd, wchar_t *file_name)
{

  FILE *file = 0;
  if (fd != -1)
    file = _fdopen(fd, "r");
  else {
    DEXIT_PROCESS(L"File descriptor invalid.", GetLastError());
  }

  if (file == 0) {
    size_t chars_converted;
    wchar_t message[255];
    swprintf_s(message, L"Invalid File: %s", file_name);
    DEXIT_PROCESS(message, GetLastError());
  }

  ibt *telemetry = (ibt *)malloc(sizeof(ibt));

  if (telemetry) {

    fread(&telemetry->header, 1, sizeof(irsdk_header), file);
    telemetry->session_string = (char *)malloc(telemetry->header.sessionInfoLen+1);
    fread(&telemetry->disk_subheader, 1, sizeof(irsdk_diskSubHeader), file);

    fseek(file, telemetry->header.sessionInfoOffset, SEEK_SET);

    fread(telemetry->session_string, 1, telemetry->header.sessionInfoLen, file);

    telemetry->session_string[telemetry->header.sessionInfoLen-1] = '\0';

    return telemetry;
  }

  int ret = 0;

}

wchar_t *num_to_month(int month)
{
  switch (month)
  {
    case 1:
      return L"January";
    case 2:
      return L"February";
    case 3:
      return L"March";
    case 4:
      return L"April";
    case 5:
      return L"May";
    case 6:
      return L"June";
    case 7:
      return L"July";
    case 8:
      return L"August";
    case 9:
      return L"September";
    case 10:
      return L"October";
    case 11:
      return L"November";
    case 12:
      return L"December";
    default:
      DEXIT_PROCESS(L"INVALID TIME MONTH", GetLastError());
  }
}

void sort_ibt_directory(wchar_t *directory)
{
  WIN32_FIND_DATA files;
  HANDLE search;
  wchar_t directory_wildcard[MAX_PATH_UNICODE];
  wchar_t filename[MAX_PATH_UNICODE];
  wchar_t extension[4];

  StringCchCopy(directory_wildcard, MAX_PATH_UNICODE, directory);

  StringCchCat(directory_wildcard, MAX_PATH_UNICODE, L"*");

  if (!PathFileExists(directory))
    /* Path length limit is 248 characters inc. null terminator */
    SHCreateDirectory(NULL, directory);

  search = FindFirstFile(directory_wildcard, &files);

  if (search == INVALID_HANDLE_VALUE) {
    DEXIT_PROCESS(L"FindFirstFile returned invalid handle.", GetLastError());
  }

  do
  {
    int len = wcsnlen(files.cFileName, MAX_PATH);
    wcsncpy(extension, files.cFileName + (len - 3), 4);

    if (lstrcmp(extension, L"ibt") == 0) {
      StringCchCopy(filename, MAX_PATH_UNICODE, directory);
      StringCchCat(filename, MAX_PATH_UNICODE, files.cFileName);
      HANDLE file_handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
                               OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
      int fd = _open_osfhandle((intptr_t)file_handle, _O_APPEND | _O_RDONLY);
      ibt *telemetry = parse_ibt(fd, filename);
      char *ir_buffer;

      size_t chars_converted;
      errno_t error;

      char vehicle_query[255];

      wchar_t vehicle_name_unicode[255];
      wchar_t track_name_unicode[255];
      wchar_t driver_idx_unicode[255];

      ir_buffer = ir_get_variable("DriverInfo:DriverCarIdx:", telemetry->session_string);

      if(FAILED(error = mbstowcs_s(&chars_converted, driver_idx_unicode,
                                   sizeof(driver_idx_unicode)/sizeof(driver_idx_unicode[0]),
                                   ir_buffer, strlen(ir_buffer)+1)))
      {
        DEXIT_PROCESS(L"mbstowcs_s failed..", GetLastError());
      }

      sprintf(vehicle_query, "DriverInfo:Drivers:CarIdx:{%d}CarScreenNameShort:", atoi(ir_buffer));

      ir_buffer = ir_get_variable(vehicle_query, telemetry->session_string);

      if (FAILED(error = mbstowcs_s(&chars_converted, vehicle_name_unicode,
                                    sizeof(vehicle_name_unicode)/sizeof(vehicle_name_unicode[0]),
                                    ir_buffer, strlen(ir_buffer)+1)))
      {
        DEXIT_PROCESS(L"mbstowcs_s failed..", GetLastError());
      }

      if (ir_buffer == 0)
        continue;

      ir_buffer = ir_get_variable("WeekendInfo:TrackDisplayName:", telemetry->session_string);

      if (FAILED(error = mbstowcs_s(&chars_converted, track_name_unicode,
                                    sizeof(track_name_unicode)/sizeof(track_name_unicode[0]),
                                    ir_buffer, strlen(ir_buffer)+1)))
      {
        DEXIT_PROCESS(L"mbstowcs_s failed..", GetLastError());
      }

      wchar_t vehicle_path[MAX_PATH_UNICODE];
      wchar_t track_path[MAX_PATH_UNICODE];

      StringCchCopy(vehicle_path, MAX_PATH_UNICODE, directory);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, vehicle_name_unicode);

      CreateDirectory(vehicle_path, NULL);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, L"\\");
      StringCchCat(vehicle_path, MAX_PATH_UNICODE, track_name_unicode);

      CreateDirectory(vehicle_path, NULL);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, L"\\");

      SYSTEMTIME date;
      int ret;
      ret = FileTimeToSystemTime(&files.ftCreationTime, &date);

      wchar_t year[5];
      _itow(date.wYear, year, 10);
      StringCchCat(vehicle_path, MAX_PATH_UNICODE, year);

      CreateDirectory(vehicle_path, NULL);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, L"\\");

      wchar_t *month = num_to_month(date.wMonth);
      StringCchCat(vehicle_path, MAX_PATH_UNICODE, month);

      CreateDirectory(vehicle_path, NULL);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, L"\\");
      StringCchCat(vehicle_path, MAX_PATH_UNICODE, files.cFileName);

      CloseHandle(file_handle);
      MoveFile(filename, vehicle_path);

      free(ir_buffer);
      free(telemetry->session_string);
      free(telemetry);
    }
  }
  while (FindNextFile(search, &files) != 0);

}

void watch_ibt_directory(wchar_t *directory, HANDLE dw_change_handle)
{
  DWORD dw_wait_status;

  if (dw_change_handle == INVALID_HANDLE_VALUE) {
    DEXIT_PROCESS(L"Invalid Handle Value", GetLastError());
  }

  dw_wait_status = WaitForSingleObject(dw_change_handle, 0);

  switch (dw_wait_status)
  {
    case WAIT_OBJECT_0:
      /* A file was created, renamed, or deleted in the directory */
      sort_ibt_directory(directory);
      if (FindNextChangeNotification(dw_change_handle) == FALSE) {
        DEXIT_PROCESS(L"FindNextChangeNotification function failed.", GetLastError());
      }
      break;

    case WAIT_OBJECT_0 + 1:
      /* A directory was created, renamed, or deleted. */
      if (FindNextChangeNotification(dw_change_handle) == FALSE) {
        DEXIT_PROCESS(L"FindNextChangeNotification function failed.", GetLastError());
      }
      break;

    case WAIT_TIMEOUT:
      return;

    default:
      return;
  }
}

void setup_weekend(configuration *config)
{
  check_track(config->db);
  config->configured = true;
}

void loop(sqlite3 *db, ws_daemon *ws, configuration *config)
{
  watch_ibt_directory(config->telemetry_path, config->dw_change_handle);
}
<commit_msg>Use exception handling during ibt sorting<commit_after>/**
*******************************************************************************
*                                                                             *
* ECU: iRacing MP4-30 Performance Analysis Project                            *
*                                                                             *
*******************************************************************************
* Copyright 2016 Adrian Garcia Cruz. All rights reserved.                     *
* Released under the BSD license. see LICENSE for more information            *
*                                                                             *
* Author: Adrian Garcia Cruz <garcia.adrian.cruz@gmail.com>                   *
*******************************************************************************
*/

#include "loop.h"

#include <irsdk/irsdk_client.h>
#include <irsdk/irsdk_defines.h>
#include <irsdk/yaml_parser.h>
#include "ir_helper.h"
#include <stdlib.h>
#include <Strsafe.h>
#include <io.h>
#include <fcntl.h>
#include <Shlobj.h>

void check_track(sqlite3 *db)
{
  static char buffer[512];
  static char sql[512];
  sqlite3_stmt *sql_stmt = {0};
  int rc = 0;

  char *ir_buffer;

  if (irsdkClient::instance().waitForData(16)) {
    ir_buffer = ir_get_variable("WeekendInfo:TrackDisplayName:", irsdk_getSessionInfoStr());
    sprintf_s(sql, "SELECT * FROM tracks WHERE name='%s'", ir_buffer);

    rc = sqlite3_prepare_v2(db, sql, sizeof(sql), &sql_stmt, NULL);
    handle_sql_rc(rc, sql, db, false, false, true);

    rc = sqlite3_step(sql_stmt);
    DEBUG_OUTA("[STARTUP]: Checking if current track is on the database\n", buffer);

    if (!handle_sql_rc(rc, sql, db, true, true, true)) {

      DEBUG_OUTA("[STARTUP]: Entry for track '%s' was not found in table `tracks`\n"
                 "[STARTUP]: Creating entry in table `tracks` for '%s'\n",
                 buffer, ir_buffer, ir_buffer);
      sprintf_s(sql, "INSERT INTO tracks(name) VALUES('%s')", ir_buffer);

      rc = sqlite3_prepare_v2(db, sql, sizeof(sql), &sql_stmt, NULL);
      handle_sql_rc(rc, sql, db, false, true, false);
      rc = sqlite3_step(sql_stmt);
      handle_sql_rc(rc, sql, db, true, true, false);

    } else {
      DEBUG_OUTA("[STARTUP]: Track %s found in database\n", buffer, ir_buffer);
      const unsigned char *sql_result = sqlite3_column_text(sql_stmt, 1);
    }

    free(ir_buffer);
  }
}

ibt *parse_ibt(intptr_t fd, wchar_t *file_name)
{

  FILE *file = 0;
  if (fd != -1)
    file = _fdopen(fd, "r");
  else {
    DEXIT_PROCESS(L"File descriptor invalid.", GetLastError());
  }

  if (file == 0) {
    size_t chars_converted;
    wchar_t message[255];
    swprintf_s(message, L"Invalid File: %s", file_name);
    DEXIT_PROCESS(message, GetLastError());
  }

  ibt *telemetry = (ibt *)malloc(sizeof(ibt));

  if (telemetry) {

    fread(&telemetry->header, 1, sizeof(irsdk_header), file);
    telemetry->session_string = (char *)malloc(telemetry->header.sessionInfoLen+1);
    fread(&telemetry->disk_subheader, 1, sizeof(irsdk_diskSubHeader), file);

    fseek(file, telemetry->header.sessionInfoOffset, SEEK_SET);

    fread(telemetry->session_string, 1, telemetry->header.sessionInfoLen, file);

    telemetry->session_string[telemetry->header.sessionInfoLen-1] = '\0';

    return telemetry;
  }

  int ret = 0;

}

wchar_t *num_to_month(int month)
{
  switch (month)
  {
    case 1:
      return L"January";
    case 2:
      return L"February";
    case 3:
      return L"March";
    case 4:
      return L"April";
    case 5:
      return L"May";
    case 6:
      return L"June";
    case 7:
      return L"July";
    case 8:
      return L"August";
    case 9:
      return L"September";
    case 10:
      return L"October";
    case 11:
      return L"November";
    case 12:
      return L"December";
    default:
      DEXIT_PROCESS(L"INVALID TIME MONTH", GetLastError());
  }
}

void sort_ibt_directory(wchar_t *directory)
{
  wchar_t debug[1024];

  WIN32_FIND_DATA files;
  HANDLE search;
  wchar_t directory_wildcard[MAX_PATH_UNICODE];
  wchar_t filename[MAX_PATH_UNICODE];
  wchar_t extension[4];

  StringCchCopy(directory_wildcard, MAX_PATH_UNICODE, directory);

  StringCchCat(directory_wildcard, MAX_PATH_UNICODE, L"*");

  if (!PathFileExists(directory))
    /* Path length limit is 248 characters inc. null terminator */
    SHCreateDirectory(NULL, directory);

  search = FindFirstFile(directory_wildcard, &files);

  if (search == INVALID_HANDLE_VALUE) {
    DEXIT_PROCESS(L"FindFirstFile returned invalid handle.", GetLastError());
  }

  do
  {
    int len = wcsnlen(files.cFileName, MAX_PATH);
    wcsncpy(extension, files.cFileName + (len - 3), 4);

    if (lstrcmp(extension, L"ibt") == 0) {
      StringCchCopy(filename, MAX_PATH_UNICODE, directory);
      StringCchCat(filename, MAX_PATH_UNICODE, files.cFileName);

      HANDLE file_handle;

      __try {
        file_handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
                                        OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
      }

      __except (EXCEPTION_EXECUTE_HANDLER) {
        if (INVALID_HANDLE_VALUE != file_handle)
          CloseHandle(file_handle);

        file_handle = INVALID_HANDLE_VALUE;
        continue;
      }

      int fd = _open_osfhandle((intptr_t)file_handle, _O_APPEND | _O_RDONLY);

      if (fd == -1) {
        if (INVALID_HANDLE_VALUE != file_handle)
          CloseHandle(file_handle);

        file_handle = INVALID_HANDLE_VALUE;
        swprintf_s(debug, L"failed to obtain file descriptor for file %s", files.cFileName);
        DEXIT_PROCESS(debug, 0);
        continue;
      }

      ibt *telemetry = parse_ibt(fd, filename);
      char *ir_buffer;

      size_t chars_converted;
      errno_t error;

      char vehicle_query[255];

      wchar_t vehicle_name_unicode[255];
      wchar_t track_name_unicode[255];
      wchar_t driver_idx_unicode[255];

      ir_buffer = ir_get_variable("DriverInfo:DriverCarIdx:", telemetry->session_string);

      if(FAILED(error = mbstowcs_s(&chars_converted, driver_idx_unicode,
                                   sizeof(driver_idx_unicode)/sizeof(driver_idx_unicode[0]),
                                   ir_buffer, strlen(ir_buffer)+1)))
      {
        DEXIT_PROCESS(L"mbstowcs_s failed..", GetLastError());
      }

      sprintf(vehicle_query, "DriverInfo:Drivers:CarIdx:{%d}CarScreenNameShort:", atoi(ir_buffer));

      ir_buffer = ir_get_variable(vehicle_query, telemetry->session_string);

      if (FAILED(error = mbstowcs_s(&chars_converted, vehicle_name_unicode,
                                    sizeof(vehicle_name_unicode)/sizeof(vehicle_name_unicode[0]),
                                    ir_buffer, strlen(ir_buffer)+1)))
      {
        DEXIT_PROCESS(L"mbstowcs_s failed..", GetLastError());
      }

      if (ir_buffer == 0)
        continue;

      ir_buffer = ir_get_variable("WeekendInfo:TrackDisplayName:", telemetry->session_string);

      if (FAILED(error = mbstowcs_s(&chars_converted, track_name_unicode,
                                    sizeof(track_name_unicode)/sizeof(track_name_unicode[0]),
                                    ir_buffer, strlen(ir_buffer)+1)))
      {
        DEXIT_PROCESS(L"mbstowcs_s failed..", GetLastError());
      }

      wchar_t vehicle_path[MAX_PATH_UNICODE];
      wchar_t track_path[MAX_PATH_UNICODE];

      StringCchCopy(vehicle_path, MAX_PATH_UNICODE, directory);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, vehicle_name_unicode);

      CreateDirectory(vehicle_path, NULL);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, L"\\");
      StringCchCat(vehicle_path, MAX_PATH_UNICODE, track_name_unicode);

      CreateDirectory(vehicle_path, NULL);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, L"\\");

      SYSTEMTIME date;
      int ret;
      ret = FileTimeToSystemTime(&files.ftCreationTime, &date);

      wchar_t year[5];
      _itow(date.wYear, year, 10);
      StringCchCat(vehicle_path, MAX_PATH_UNICODE, year);

      CreateDirectory(vehicle_path, NULL);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, L"\\");

      wchar_t *month = num_to_month(date.wMonth);
      StringCchCat(vehicle_path, MAX_PATH_UNICODE, month);

      CreateDirectory(vehicle_path, NULL);

      StringCchCat(vehicle_path, MAX_PATH_UNICODE, L"\\");
      StringCchCat(vehicle_path, MAX_PATH_UNICODE, files.cFileName);

      CloseHandle(file_handle);
      MoveFile(filename, vehicle_path);

      free(ir_buffer);
      free(telemetry->session_string);
      free(telemetry);
    }
  }
  while (FindNextFile(search, &files) != 0);

}

void watch_ibt_directory(wchar_t *directory, HANDLE dw_change_handle)
{
  DWORD dw_wait_status;

  if (dw_change_handle == INVALID_HANDLE_VALUE) {
    DEXIT_PROCESS(L"Invalid Handle Value", GetLastError());
  }

  dw_wait_status = WaitForSingleObject(dw_change_handle, 0);

  switch (dw_wait_status)
  {
    case WAIT_OBJECT_0:
      /* A file was created, renamed, or deleted in the directory */
      sort_ibt_directory(directory);
      if (FindNextChangeNotification(dw_change_handle) == FALSE) {
        DEXIT_PROCESS(L"FindNextChangeNotification function failed.", GetLastError());
      }
      break;

    case WAIT_OBJECT_0 + 1:
      /* A directory was created, renamed, or deleted. */
      if (FindNextChangeNotification(dw_change_handle) == FALSE) {
        DEXIT_PROCESS(L"FindNextChangeNotification function failed.", GetLastError());
      }
      break;

    case WAIT_TIMEOUT:
      return;

    default:
      return;
  }
}

void setup_weekend(configuration *config)
{
  check_track(config->db);
  config->configured = true;
}

void loop(sqlite3 *db, ws_daemon *ws, configuration *config)
{
  watch_ibt_directory(config->telemetry_path, config->dw_change_handle);
}
<|endoftext|>


<commit_before>// CreditMetrics.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

template <class R> class CSV
{
	public:
		CSV(const string& filename, bool header)
		{
			ifstream file(filename);
			if (!file.good())
			{
				throw runtime_error("File does not exist");
			}
			bool skip = true;
			while (!file.eof())
			{
				string strline;
				getline(file, strline);
				if (skip)
				{
					skip = false;
					continue;
				}
				if (strline.empty())
				{
					continue;
				}
				stringstream streamline(strline);
				vector<string> cells;
				while (!streamline.eof())
				{
					string cell;
					getline(streamline, cell, ',');
					if (cell != "")
					{
						cells.push_back(cell);
					}
				}
				if (cells.empty())
				{
					continue;
				}
				rows.push_back(R(cells));
			}
		}
		size_t size() { return rows.size(); }
		R& get(size_t i) { return rows[i]; }
	private:
		vector<R> rows;
};
class Issuer
{
	public:
		Issuer(vector<string>& cells):
			name(cells.at(0)),
			rating(cells.at(1)),
			industry(cells.at(2))
		{}
		const string name;
		const string rating;
		const string industry;
};
class Issuers : public CSV<Issuer>
{
	public:
		Issuers() : CSV("issuers.csv", true) { }
		Issuer* getByName(string name)
		{
			for (int i = 0, n = size(); i < n; i++)
			{
				Issuer& issuer = get(i);
				if(issuer.name == name)
					return &issuer;
			}
			return nullptr;
		}
};
int main(int argc, char* argv[])
{
	try
	{
		Issuers issuers;
		for (int i = 0, n = issuers.size(); i < n; i++)
		{
			Issuer issuer = issuers.get(i);
			cout << issuer.name << "," << issuer.rating << "," << issuer.industry << "\n";
		}
	}
	catch (const exception &e)
	{
		cerr << "error: " << e.what() << "\n";
	}
	getchar();
}<commit_msg>Correcting warnings<commit_after>// CreditMetrics.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

template <class R> class CSV
{
	public:
		CSV(const string& filename, bool header)
		{
			ifstream file(filename);
			if (!file.good())
			{
				throw runtime_error("File does not exist");
			}
			bool skip = true;
			while (!file.eof())
			{
				string strline;
				getline(file, strline);
				if (skip)
				{
					skip = false;
					continue;
				}
				if (strline.empty())
				{
					continue;
				}
				stringstream streamline(strline);
				vector<string> cells;
				while (!streamline.eof())
				{
					string cell;
					getline(streamline, cell, ',');
					if (cell != "")
					{
						cells.push_back(cell);
					}
				}
				if (cells.empty())
				{
					continue;
				}
				rows.push_back(R(cells));
			}
		}
		size_t size() { return rows.size(); }
		R& get(size_t i) { return rows[i]; }
	private:
		vector<R> rows;
};
class Issuer
{
	public:
		Issuer(vector<string>& cells):
			name(cells.at(0)),
			rating(cells.at(1)),
			industry(cells.at(2))
		{}
		const string name;
		const string rating;
		const string industry;
};
class Issuers : public CSV<Issuer>
{
	public:
		Issuers() : CSV("issuers.csv", true) { }
		Issuer* getByName(string name)
		{
			for (size_t i = 0, n = size(); i < n; i++)
			{
				Issuer& issuer = get(i);
				if(issuer.name == name)
					return &issuer;
			}
			return nullptr;
		}
};
int main(int argc, char* argv[])
{
	try
	{
		Issuers issuers;
		for (size_t i = 0, n = issuers.size(); i < n; i++)
		{
			Issuer issuer = issuers.get(i);
			cout << issuer.name << "," << issuer.rating << "," << issuer.industry << "\n";
		}
	}
	catch (const exception &e)
	{
		cerr << "error: " << e.what() << "\n";
	}
	getchar();
}<|endoftext|>