<commit_before>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2014, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#ifdef __linux__
#include <QDebug>
#include "LuminaOS.h"
#include <unistd.h>
#include <stdio.h> // Needed for BUFSIZ

//can't read xbrightness settings - assume invalid until set
static int screenbrightness = -1;

QString LOS::OSName(){ return "Slackware Linux"; }

//OS-specific prefix(s)
// NOTE: PREFIX, L_ETCDIR, L_SHAREDIR are defined in the OS-detect.pri project file and passed in
QString LOS::LuminaShare(){ return (L_SHAREDIR+"/lumina-desktop/"); } //Install dir for Lumina share files
QString LOS::AppPrefix(){ return "/usr/"; } //Prefix for applications
QString LOS::SysPrefix(){ return "/etc/"; } //Prefix for system

//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return ""; } //graphical app/pkg manager
//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
QStringList LOS::RSSFeeds(){ return QStringList(); }

// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
    //Returns: QStringList[<type>::::<filesystem>::::<path>]
      //Note: <type> = [USB, HDRIVE, DVD, SDCARD, UNKNOWN]
  QStringList devs = LUtils::getCmdOutput("mount");
  //Now check the output
  for(int i=0; i<devs.length(); i++){
   if(devs[i].startsWith("/dev/")){
      devs[i] = devs[i].simplified();
      QString type = devs[i].section(" ",0,0);
      type.remove("/dev/");
      //Determine the type of hardware device based on the dev node
      if(type.startsWith("sd") || type.startsWith("nvme")){ type = "HDRIVE"; }
      else if(type.startsWith("sr")){ type="DVD"; }
      else if(type.contains("mapper")){ type="LVM"; }
      else{ type = "UNKNOWN"; }
      //Now put the device in the proper output format
      devs[i] = type+"::::"+devs[i].section(" ",4,4)+"::::"+devs[i].section(" ",2,2);
    }else{
    //invalid device - remove it from the list
      devs.removeAt(i);
      i--;
    }
  }
  return devs;
}

//Read screen brightness information
int LOS::ScreenBrightness(){
   //Returns: Screen Brightness as a percentage (0-100, with -1 for errors)
  if(screenbrightness==-1){
    if(QFile::exists(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/.currentxbrightness")){
      int val = LUtils::readFile(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/.currentxbrightness").join("").simplified().toInt();
      screenbrightness = val;
    }
  }
  return screenbrightness;

}

//Set screen brightness
void LOS::setScreenBrightness(int percent){
  //ensure bounds
  if(percent<0){percent=0;}
  else if(percent>100){ percent=100; }
  // float pf = percent/100.0; //convert to a decimel
  //Run the command
  QString cmd = "xbacklight -set %1";
  // cmd = cmd.arg( QString::number( int(65535*pf) ) );
  cmd = cmd.arg( QString::number( percent ) );
  int ret = LUtils::runCmd(cmd);
  //Save the result for later
  if(ret!=0){ screenbrightness = -1; }
  else{ screenbrightness = percent; }
  LUtils::writeFile(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/.currentxbrightness", QStringList() << QString::number(screenbrightness), true);

}

//Read the current volume
int LOS::audioVolume(){ //Returns: audio volume as a percentage (0-100, with -1 for errors)
QString info = LUtils::getCmdOutput("amixer get Master").join("").simplified();;
  int out = -1;
  int start_position, end_position;
  QString current_volume;
  if(!info.isEmpty()){
     start_position = info.indexOf("[");
     start_position++;
     end_position = info.indexOf("%");
     current_volume = info.mid(start_position, end_position - start_position);
     out = current_volume.toInt();
  }
  return out;

}

//Set the current volume
void LOS::setAudioVolume(int percent){
  if(percent<0){percent=0;}
  else if(percent>100){percent=100;}
  QString info = "amixer set Master " + QString::number(percent) + "%";
  //Run Command
  LUtils::runCmd(info);
}

//Change the current volume a set amount (+ or -)
void LOS::changeAudioVolume(int percentdiff){
  int old_volume = audioVolume();
  int new_volume = old_volume + percentdiff;
  if (new_volume < 0)
      new_volume = 0;
  if (new_volume > 100)
      new_volume = 100;
  qDebug() << "Setting new volume to: " << new_volume;
  setAudioVolume(new_volume);
}

//Check if a graphical audio mixer is installed
bool LOS::hasMixerUtility(){
  return QFile::exists(LOS::AppPrefix() + "bin/pavucontrol");
}

//Launch the graphical audio mixer utility
void LOS::startMixerUtility(){
  QProcess::startDetached(LOS::AppPrefix() + "bin/pavucontrol");
}

//Check for user system permission (shutdown/restart)
bool LOS::userHasShutdownAccess(){
  return true; //not implemented yet
}

//Check for whether the system is safe to power off (no updates being perfomed)
bool LOS::systemPerformingUpdates(){
  return false; //Not implemented yet
}

//Return the details of any updates which are waiting to apply on shutdown
QString LOS::systemPendingUpdates(){
  return "";
}

//System Shutdown
void LOS::systemShutdown(bool){ //start poweroff sequence
  //INPUT: skip updates (true/false)
  QProcess::startDetached("dbus-send --system --print-reply=literal --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Stop");
}

//System Restart
void LOS::systemRestart(bool){ //start reboot sequence
  //INPUT: skip updates (true/false)
  QProcess::startDetached("dbus-send --system --print-reply=literal --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Restart");
}

//Check for suspend support
bool LOS::systemCanSuspend(){
  return false;
}

//Put the system into the suspend state
void LOS::systemSuspend(){

}

//Battery Availability
bool LOS::hasBattery(){
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  bool no_battery = my_status.contains("No support");
  if (no_battery) return false;
  return true;
}

//Battery Charge Level
int LOS::batteryCharge(){ //Returns: percent charge (0-100), anything outside that range is counted as an error
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  int my_start = my_status.indexOf("%");
  // get the number right before the % sign
  int my_end = my_start;
  my_start--;
  while ( (my_status[my_start] != ' ') && (my_start > 0) )
      my_start--;
  my_start++;
  int my_charge = my_status.mid(my_start, my_end - my_start).toInt();
  if ( (my_charge < 0) || (my_charge > 100) ) return -1;
  return my_charge;
}

//Battery Charging State
// Many possible values are returned if the laptop is plugged in
// these include "Unknown, Full and No support.
// However, it seems just one status is returned when running
// on battery and that is "Discharging". So if the value we get
// is NOT Discharging then we assume the battery is charging.
bool LOS::batteryIsCharging(){
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  bool discharging = my_status.contains("Discharging");
  if (discharging) return false;
  return true;
}

//Battery Time Remaining
int LOS::batterySecondsLeft(){ //Returns: estimated number of seconds remaining
  return 0; //not implemented yet for Linux
}

//File Checksums
QStringList LOS::Checksums(QStringList filepaths){ //Return: checksum of the input file
  QStringList info = LUtils::getCmdOutput("md5sum \""+filepaths.join("\" \"")+"\"");
  for(int i=0; i<info.length(); i++){
    // first: md5sum: = error ; second: there's always one empty entry generated by getCmdOutput
    if( info[i].startsWith("md5sum:") || info[i].isEmpty()){ info.removeAt(i); i--; }
    else{
      //Strip out the extra information
      info[i] = info[i].section(" ",0,0);
    }
  }
 return info;
}

//file system capacity
QString LOS::FileSystemCapacity(QString dir) { //Return: percentage capacity as give by the df command
  QStringList mountInfo = LUtils::getCmdOutput("df \"" + dir+"\"");
  QString::SectionFlag skipEmpty = QString::SectionSkipEmpty;
  //we take the 5th word on the 2 line
  QString capacity = mountInfo[1].section(" ",4,4, skipEmpty) + " used";
  return capacity;
}

QStringList LOS::CPUTemperatures(){ //Returns: List containing the temperature of any CPU's ("50C" for example)
  return QStringList(); //not implemented yet
}

int LOS::CPUUsagePercent(){ //Returns: Overall percentage of the amount of CPU cycles in use (-1 for errors)
  return -1; //not implemented yet
}

int LOS::MemoryUsagePercent(){
  return -1; //not implemented yet
}

QStringList LOS::DiskUsage(){ //Returns: List of current read/write stats for each device
  return QStringList(); //not implemented yet
}

#endif
<commit_msg>OS: Support suspend on Slackware<commit_after>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2014, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#ifdef __linux__
#include <QDebug>
#include "LuminaOS.h"
#include <unistd.h>
#include <stdio.h> // Needed for BUFSIZ

//can't read xbrightness settings - assume invalid until set
static int screenbrightness = -1;

QString LOS::OSName(){ return "Slackware Linux"; }

//OS-specific prefix(s)
// NOTE: PREFIX, L_ETCDIR, L_SHAREDIR are defined in the OS-detect.pri project file and passed in
QString LOS::LuminaShare(){ return (L_SHAREDIR+"/lumina-desktop/"); } //Install dir for Lumina share files
QString LOS::AppPrefix(){ return "/usr/"; } //Prefix for applications
QString LOS::SysPrefix(){ return "/etc/"; } //Prefix for system

//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return ""; } //graphical app/pkg manager
//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
QStringList LOS::RSSFeeds(){ return QStringList(); }

// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
    //Returns: QStringList[<type>::::<filesystem>::::<path>]
      //Note: <type> = [USB, HDRIVE, DVD, SDCARD, UNKNOWN]
  QStringList devs = LUtils::getCmdOutput("mount");
  //Now check the output
  for(int i=0; i<devs.length(); i++){
   if(devs[i].startsWith("/dev/")){
      devs[i] = devs[i].simplified();
      QString type = devs[i].section(" ",0,0);
      type.remove("/dev/");
      //Determine the type of hardware device based on the dev node
      if(type.startsWith("sd") || type.startsWith("nvme")){ type = "HDRIVE"; }
      else if(type.startsWith("sr")){ type="DVD"; }
      else if(type.contains("mapper")){ type="LVM"; }
      else{ type = "UNKNOWN"; }
      //Now put the device in the proper output format
      devs[i] = type+"::::"+devs[i].section(" ",4,4)+"::::"+devs[i].section(" ",2,2);
    }else{
    //invalid device - remove it from the list
      devs.removeAt(i);
      i--;
    }
  }
  return devs;
}

//Read screen brightness information
int LOS::ScreenBrightness(){
   //Returns: Screen Brightness as a percentage (0-100, with -1 for errors)
  if(screenbrightness==-1){
    if(QFile::exists(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/.currentxbrightness")){
      int val = LUtils::readFile(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/.currentxbrightness").join("").simplified().toInt();
      screenbrightness = val;
    }
  }
  return screenbrightness;

}

//Set screen brightness
void LOS::setScreenBrightness(int percent){
  //ensure bounds
  if(percent<0){percent=0;}
  else if(percent>100){ percent=100; }
  // float pf = percent/100.0; //convert to a decimel
  //Run the command
  QString cmd = "xbacklight -set %1";
  // cmd = cmd.arg( QString::number( int(65535*pf) ) );
  cmd = cmd.arg( QString::number( percent ) );
  int ret = LUtils::runCmd(cmd);
  //Save the result for later
  if(ret!=0){ screenbrightness = -1; }
  else{ screenbrightness = percent; }
  LUtils::writeFile(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/.currentxbrightness", QStringList() << QString::number(screenbrightness), true);

}

//Read the current volume
int LOS::audioVolume(){ //Returns: audio volume as a percentage (0-100, with -1 for errors)
QString info = LUtils::getCmdOutput("amixer get Master").join("").simplified();;
  int out = -1;
  int start_position, end_position;
  QString current_volume;
  if(!info.isEmpty()){
     start_position = info.indexOf("[");
     start_position++;
     end_position = info.indexOf("%");
     current_volume = info.mid(start_position, end_position - start_position);
     out = current_volume.toInt();
  }
  return out;

}

//Set the current volume
void LOS::setAudioVolume(int percent){
  if(percent<0){percent=0;}
  else if(percent>100){percent=100;}
  QString info = "amixer set Master " + QString::number(percent) + "%";
  //Run Command
  LUtils::runCmd(info);
}

//Change the current volume a set amount (+ or -)
void LOS::changeAudioVolume(int percentdiff){
  int old_volume = audioVolume();
  int new_volume = old_volume + percentdiff;
  if (new_volume < 0)
      new_volume = 0;
  if (new_volume > 100)
      new_volume = 100;
  qDebug() << "Setting new volume to: " << new_volume;
  setAudioVolume(new_volume);
}

//Check if a graphical audio mixer is installed
bool LOS::hasMixerUtility(){
  return QFile::exists(LOS::AppPrefix() + "bin/pavucontrol");
}

//Launch the graphical audio mixer utility
void LOS::startMixerUtility(){
  QProcess::startDetached(LOS::AppPrefix() + "bin/pavucontrol");
}

//Check for user system permission (shutdown/restart)
bool LOS::userHasShutdownAccess(){
  return true; //not implemented yet
}

//Check for whether the system is safe to power off (no updates being perfomed)
bool LOS::systemPerformingUpdates(){
  return false; //Not implemented yet
}

//Return the details of any updates which are waiting to apply on shutdown
QString LOS::systemPendingUpdates(){
  return "";
}

//System Shutdown
void LOS::systemShutdown(bool){ //start poweroff sequence
  //INPUT: skip updates (true/false)
  QProcess::startDetached("dbus-send --system --print-reply=literal --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Stop");
}

//System Restart
void LOS::systemRestart(bool){ //start reboot sequence
  //INPUT: skip updates (true/false)
  QProcess::startDetached("dbus-send --system --print-reply=literal --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Restart");
}

//Check for suspend support
bool LOS::systemCanSuspend(){
  return true;
}

//Put the system into the suspend state
void LOS::systemSuspend(){
  QProcess::startDetached("dbus-send --system --print-reply=literal --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower.Suspend");
}

//Battery Availability
bool LOS::hasBattery(){
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  bool no_battery = my_status.contains("No support");
  if (no_battery) return false;
  return true;
}

//Battery Charge Level
int LOS::batteryCharge(){ //Returns: percent charge (0-100), anything outside that range is counted as an error
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  int my_start = my_status.indexOf("%");
  // get the number right before the % sign
  int my_end = my_start;
  my_start--;
  while ( (my_status[my_start] != ' ') && (my_start > 0) )
      my_start--;
  my_start++;
  int my_charge = my_status.mid(my_start, my_end - my_start).toInt();
  if ( (my_charge < 0) || (my_charge > 100) ) return -1;
  return my_charge;
}

//Battery Charging State
// Many possible values are returned if the laptop is plugged in
// these include "Unknown, Full and No support.
// However, it seems just one status is returned when running
// on battery and that is "Discharging". So if the value we get
// is NOT Discharging then we assume the battery is charging.
bool LOS::batteryIsCharging(){
  QString my_status = LUtils::getCmdOutput("acpi -b").join("");
  bool discharging = my_status.contains("Discharging");
  if (discharging) return false;
  return true;
}

//Battery Time Remaining
int LOS::batterySecondsLeft(){ //Returns: estimated number of seconds remaining
  return 0; //not implemented yet for Linux
}

//File Checksums
QStringList LOS::Checksums(QStringList filepaths){ //Return: checksum of the input file
  QStringList info = LUtils::getCmdOutput("md5sum \""+filepaths.join("\" \"")+"\"");
  for(int i=0; i<info.length(); i++){
    // first: md5sum: = error ; second: there's always one empty entry generated by getCmdOutput
    if( info[i].startsWith("md5sum:") || info[i].isEmpty()){ info.removeAt(i); i--; }
    else{
      //Strip out the extra information
      info[i] = info[i].section(" ",0,0);
    }
  }
 return info;
}

//file system capacity
QString LOS::FileSystemCapacity(QString dir) { //Return: percentage capacity as give by the df command
  QStringList mountInfo = LUtils::getCmdOutput("df \"" + dir+"\"");
  QString::SectionFlag skipEmpty = QString::SectionSkipEmpty;
  //we take the 5th word on the 2 line
  QString capacity = mountInfo[1].section(" ",4,4, skipEmpty) + " used";
  return capacity;
}

QStringList LOS::CPUTemperatures(){ //Returns: List containing the temperature of any CPU's ("50C" for example)
  return QStringList(); //not implemented yet
}

int LOS::CPUUsagePercent(){ //Returns: Overall percentage of the amount of CPU cycles in use (-1 for errors)
  return -1; //not implemented yet
}

int LOS::MemoryUsagePercent(){
  return -1; //not implemented yet
}

QStringList LOS::DiskUsage(){ //Returns: List of current read/write stats for each device
  return QStringList(); //not implemented yet
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2021 Google LLC
 *
 * 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 "fcp/client/engine/caching_error_reporter.h"

#include <string>

#include "gtest/gtest.h"
#include "absl/strings/str_cat.h"
#include "fcp/testing/testing.h"
#include "tensorflow/lite/core/api/error_reporter.h"

namespace fcp {
namespace client {
namespace engine {
namespace {

using ::testing::IsEmpty;

TEST(CachingErrorReporterTest, CachingMultiple) {
  CachingErrorReporter reporter;
  std::string first_error = "Op a is not found.";
  TF_LITE_REPORT_ERROR(&reporter, "%s%d", first_error.c_str(), 1);
  std::string second_error = "Op b is not found.";
  TF_LITE_REPORT_ERROR(&reporter, "%s%d", second_error.c_str(), 2);
  EXPECT_THAT(reporter.GetFirstErrorMessage(), absl::StrCat(first_error, "1"));
}

TEST(CachingErrorReporterTest, Empty) {
  CachingErrorReporter reporter;
  EXPECT_THAT(reporter.GetFirstErrorMessage(), IsEmpty());
}

}  // anonymous namespace
}  // namespace engine
}  // namespace client
}  // namespace fcp
<commit_msg>TFLite Micro introduced the macro TF_LITE_REPORT_ERROR as an attempt to wrap the error logging functionality to check for TF_LITE_STRIP_ERROR_STRINGS (an ifdef var to ignore calls to message logging API).<commit_after>/*
 * Copyright 2021 Google LLC
 *
 * 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 "fcp/client/engine/caching_error_reporter.h"

#include <string>

#include "gtest/gtest.h"
#include "absl/strings/str_cat.h"
#include "fcp/testing/testing.h"
#include "tensorflow/lite/core/api/error_reporter.h"

namespace fcp {
namespace client {
namespace engine {
namespace {

using ::testing::IsEmpty;

TEST(CachingErrorReporterTest, CachingMultiple) {
  CachingErrorReporter reporter;
  std::string first_error = "Op a is not found.";
  static_cast<tflite::ErrorReporter*>(&reporter)->Report(
      "%s%d", first_error.c_str(), 1);
  std::string second_error = "Op b is not found.";
  static_cast<tflite::ErrorReporter*>(&reporter)->Report(
      "%s%d", second_error.c_str(), 2);
  EXPECT_THAT(reporter.GetFirstErrorMessage(), absl::StrCat(first_error, "1"));
}

TEST(CachingErrorReporterTest, Empty) {
  CachingErrorReporter reporter;
  EXPECT_THAT(reporter.GetFirstErrorMessage(), IsEmpty());
}

}  // anonymous namespace
}  // namespace engine
}  // namespace client
}  // namespace fcp
<|endoftext|>


<commit_before>/*
 * Copyright 2022 Google LLC
 *
 * 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 "fcp/client/http/curl/curl_http_request_handle.h"

#include <memory>
#include <optional>
#include <string>
#include <utility>

#include "absl/strings/match.h"
#include "curl/curl.h"
#include "fcp/base/monitoring.h"
#include "fcp/client/http/curl/curl_api.h"
#include "fcp/client/http/curl/curl_header_parser.h"
#include "fcp/client/http/curl/curl_http_response.h"
#include "fcp/client/http/http_client_util.h"

namespace fcp::client::http::curl {
namespace {
// A type check for the macro.
inline CURLcode AsCode(CURLcode code) { return code; }
/**
 * Macro which allows to check for a status code and return from the
 * current method if not OK. Example:
 *
 *     Status DoSomething() {
 *       CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(...));
 *     }
 */
#define CURL_RETURN_IF_ERROR(expr)                        \
  do {                                                    \
    CURLcode __code = AsCode(expr);                       \
    if (__code != CURLE_OK) {                             \
      FCP_LOG(ERROR) << "Easy handle failed with "        \
                     << CurlEasyHandle::StrError(__code); \
      return (__code);                                    \
    }                                                     \
  } while (false)
}  // namespace

size_t CurlHttpRequestHandle::HeaderCallback(char* buffer, size_t size,
                                             size_t n_items, void* user_data) {
  auto self = static_cast<CurlHttpRequestHandle*>(user_data);
  std::string str_header(static_cast<char*>(buffer), size * n_items);

  self->header_parser_.ParseHeader(str_header);
  if (!self->header_parser_.IsLastHeader()) {
    return size * n_items;
  }

  self->response_ =
      std::make_unique<CurlHttpResponse>(self->header_parser_.GetStatusCode(),
                                         self->header_parser_.GetHeaderList());

  FCP_CHECK(self->callback_ != nullptr);
  absl::Status status =
      self->callback_->OnResponseStarted(*self->request_, *self->response_);

  if (!status.ok()) {
    FCP_LOG(ERROR) << "Called OnResponseStarted. Received status: " << status;
    self->callback_->OnResponseError(*self->request_, status);
  }

  return size * n_items;
}

size_t CurlHttpRequestHandle::DownloadCallback(void* body, size_t size,
                                               size_t nmemb, void* user_data) {
  auto self = static_cast<CurlHttpRequestHandle*>(user_data);
  absl::string_view str_body(static_cast<char*>(body), size * nmemb);

  absl::Status status = self->callback_->OnResponseBody(
      *self->request_, *self->response_, str_body);

  if (!status.ok()) {
    FCP_LOG(ERROR) << "Called OnResponseBody. Received status: " << status;
    self->callback_->OnResponseBodyError(*self->request_, *self->response_,
                                         status);
  }

  return size * nmemb;
}

size_t CurlHttpRequestHandle::UploadCallback(char* buffer, size_t size,
                                             size_t num, void* user_data) {
  auto self = static_cast<CurlHttpRequestHandle*>(user_data);
  size_t buffer_size = size * num;

  absl::StatusOr<int64_t> read_size =
      self->request_->ReadBody(buffer, buffer_size);
  if (read_size.ok()) {
    return read_size.value();
  } else if (read_size.status().code() == absl::StatusCode::kOutOfRange) {
    return 0;
  }
  return CURL_READFUNC_ABORT;
}

size_t CurlHttpRequestHandle::ProgressCallback(void* user_data,
                                               curl_off_t dltotal,
                                               curl_off_t dlnow,
                                               curl_off_t ultotal,
                                               curl_off_t ulnow) {
  auto self = static_cast<CurlHttpRequestHandle*>(user_data);
  absl::MutexLock lock(&self->mutex_);
  // Abort is any number except zero.
  return (self->is_cancelled_) ? 1 : 0;
}

CurlHttpRequestHandle::CurlHttpRequestHandle(
    std::unique_ptr<HttpRequest> request,
    std::unique_ptr<CurlEasyHandle> easy_handle,
    const std::string& test_cert_path)
    : request_(std::move(request)),
      response_(nullptr),
      easy_handle_(std::move(easy_handle)),
      callback_(nullptr),
      is_being_performed_(false),
      is_completed_(false),
      is_cancelled_(false),
      header_list_(nullptr) {
  FCP_CHECK(request_ != nullptr);
  FCP_CHECK(easy_handle_ != nullptr);

  CURLcode code = InitializeConnection(test_cert_path);
  if (code != CURLE_OK) {
    FCP_LOG(ERROR) << "easy_handle initialization failed with code "
                   << CurlEasyHandle::StrError(code);
    FCP_LOG(ERROR) << error_buffer_;
    callback_->OnResponseError(*request_, absl::InternalError(error_buffer_));
    return;
  }
}

CurlHttpRequestHandle::~CurlHttpRequestHandle() {
  curl_slist_free_all(header_list_);
}

void CurlHttpRequestHandle::Cancel() {
  absl::MutexLock lock(&mutex_);

  if (callback_ == nullptr || is_cancelled_ || is_completed_) {
    return;
  }
  if (response_ != nullptr) {
    callback_->OnResponseBodyError(*request_, *response_,
                                   absl::CancelledError());
  } else {
    callback_->OnResponseError(*request_, absl::CancelledError());
  }
  is_cancelled_ = true;
}

void CurlHttpRequestHandle::MarkAsCompleted() {
  absl::MutexLock lock(&mutex_);

  FCP_CHECK(callback_ != nullptr);
  if (!is_cancelled_ && !is_completed_) {
    FCP_CHECK(response_ != nullptr);
    callback_->OnResponseCompleted(*request_, *response_);
  }
  is_completed_ = true;
}

absl::Status CurlHttpRequestHandle::AddToMulti(CurlMultiHandle* multi_handle,
                                               HttpRequestCallback* callback) {
  absl::MutexLock lock(&mutex_);

  FCP_CHECK(callback != nullptr);
  FCP_CHECK(multi_handle != nullptr);

  if (is_cancelled_) {
    callback->OnResponseError(*request_, absl::CancelledError());
    return absl::CancelledError();
  } else if (is_being_performed_ || is_completed_) {
    return absl::ResourceExhaustedError(
        "The handle was previously passed to another PerformRequests call.");
  }

  is_being_performed_ = true;
  callback_ = callback;

  CURLMcode code = multi_handle->AddEasyHandle(easy_handle_.get());
  if (code != CURLM_OK) {
    FCP_LOG(ERROR) << "AddEasyHandle failed with code " << code;
    FCP_LOG(ERROR) << error_buffer_;
    callback_->OnResponseError(*request_, absl::InternalError(error_buffer_));
    return absl::InternalError(error_buffer_);
  }

  return absl::OkStatus();
}

void CurlHttpRequestHandle::RemoveFromMulti(CurlMultiHandle* multi_handle) {
  absl::MutexLock lock(&mutex_);

  FCP_CHECK(multi_handle != nullptr);
  CURLMcode code = multi_handle->RemoveEasyHandle(easy_handle_.get());
  if (code != CURLM_OK) {
    FCP_LOG(ERROR) << "RemoveEasyHandle failed with code "
                   << CurlMultiHandle::StrError(code);
    FCP_LOG(ERROR) << error_buffer_;
  }
}

HttpRequestHandle::SentReceivedBytes
CurlHttpRequestHandle::TotalSentReceivedBytes() const {
  absl::MutexLock lock(&mutex_);
  curl_off_t total_sent_bytes = 0;
  CURLcode code =
      easy_handle_->GetInfo(CURLINFO_SIZE_UPLOAD_T, &total_sent_bytes);
  if (code != CURLE_OK) {
    FCP_LOG(ERROR) << "TotalSentBytes failed with code " << code;
    FCP_LOG(ERROR) << error_buffer_;
  }
  curl_off_t total_received_bytes = 0;
  code = easy_handle_->GetInfo(CURLINFO_SIZE_DOWNLOAD_T, &total_received_bytes);
  if (code != CURLE_OK) {
    FCP_LOG(ERROR) << "TotalReceivedBytes failed with code " << code;
    FCP_LOG(ERROR) << error_buffer_;
  }
  return {.sent_bytes = total_sent_bytes,
          .received_bytes = total_received_bytes};
}

CURLcode CurlHttpRequestHandle::InitializeConnection(
    const std::string& test_cert_path) {
  error_buffer_[0] = 0;
  // Needed to read an error message.
  CURL_RETURN_IF_ERROR(
      easy_handle_->SetOpt(CURLOPT_ERRORBUFFER, error_buffer_));

  // Skip all signal handling because is not thread-safe.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_NOSIGNAL, 1L));

  CURL_RETURN_IF_ERROR(
      easy_handle_->SetOpt(CURLOPT_URL, std::string(request_->uri())));

  // Forces curl to follow redirects.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_FOLLOWLOCATION, 1L));

  // Suppresses headers added by a proxy.
  CURL_RETURN_IF_ERROR(
      easy_handle_->SetOpt(CURLOPT_SUPPRESS_CONNECT_HEADERS, 1L));

  // Force curl to verify the ssl connection.
  CURL_RETURN_IF_ERROR(
      test_cert_path.empty()
          ? easy_handle_->SetOpt(CURLOPT_CAINFO, nullptr)
          : easy_handle_->SetOpt(CURLOPT_CAINFO, test_cert_path));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_SSL_VERIFYPEER, 2L));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_SSL_VERIFYHOST, 1L));

  // Force curl to never timeout.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_TIMEOUT_MS,
                                            std::numeric_limits<int>::max()));

  // Called when a response header received.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(
      CURLOPT_HEADERFUNCTION, &CurlHttpRequestHandle::HeaderCallback));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_HEADERDATA, this));

  // Called when a response body received.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(
      CURLOPT_WRITEFUNCTION, &CurlHttpRequestHandle::DownloadCallback));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_WRITEDATA, this));

  // Called to send a request body
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(
      CURLOPT_READFUNCTION, &CurlHttpRequestHandle::UploadCallback));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_READDATA, this));

  // Called periodically. We use it to check whether the request is cancelled.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(
      CURLOPT_XFERINFOFUNCTION, &CurlHttpRequestHandle::ProgressCallback));
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_XFERINFODATA, this));
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_NOPROGRESS, 0L));

  // Private storage. Used by a multi-handle.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_PRIVATE, this));

  switch (request_->method()) {
    case HttpRequest::Method::kGet:
      CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_HTTPGET, 1L));
      break;
    case HttpRequest::Method::kHead:
      CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_NOBODY, 1L));
      break;
    case HttpRequest::Method::kPost:
      CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_POST, 1L));
      // Forces curl to use the callback.
      CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_POSTFIELDS, nullptr));
      break;
    case HttpRequest::Method::kPut:
    case HttpRequest::Method::kPatch:
    case HttpRequest::Method::kDelete:
      // TODO(team): Implement the requests when they are needed
      FCP_LOG(ERROR) << "Unsupported request type";
      return CURLE_UNSUPPORTED_PROTOCOL;
  }

  return InitializeHeaders(request_->extra_headers());
}

CURLcode CurlHttpRequestHandle::InitializeHeaders(
    const HeaderList& extra_headers) {
  // If no "Accept-Encoding" request header is explicitly specified
  // advertise an "Accept-Encoding: gzip" else leave decoded.
  std::optional<std::string> accept_encoding =
      FindHeader(request_->extra_headers(), kAcceptEncodingHdr);
  if (!accept_encoding.has_value()) {
    // Libcurl is responsible for the encoding.
    CURL_RETURN_IF_ERROR(
        easy_handle_->SetOpt(CURLOPT_ACCEPT_ENCODING, kGzipEncodingHdrValue));
    header_parser_.UseCurlEncoding();
  } else {
    // The caller is responsible for the encoding.
    CURL_RETURN_IF_ERROR(
        easy_handle_->SetOpt(CURLOPT_ACCEPT_ENCODING, nullptr));
  }

  for (auto& [key, value] : extra_headers) {
    if (absl::EqualsIgnoreCase(key, kAcceptEncodingHdr)) {
      continue;
    } else if (absl::EqualsIgnoreCase(key, kContentLengthHdr)) {
      // For post less than 2GB
      CURL_RETURN_IF_ERROR(
          easy_handle_->SetOpt(CURLOPT_POSTFIELDSIZE, std::stol(value)));
    } else {
      curl_slist* tmp = curl_slist_append(
          header_list_, absl::StrCat(key, ": ", value).c_str());
      FCP_CHECK(tmp != nullptr);
      header_list_ = tmp;
    }
  }

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_HTTPHEADER, header_list_));
  return CURLE_OK;
}
}  // namespace fcp::client::http::curl
<commit_msg>Return an error when response_ is nullptr instead of crashing. This happens when server is inaccessible.<commit_after>/*
 * Copyright 2022 Google LLC
 *
 * 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 "fcp/client/http/curl/curl_http_request_handle.h"

#include <memory>
#include <optional>
#include <string>
#include <utility>

#include "absl/strings/match.h"
#include "curl/curl.h"
#include "fcp/base/monitoring.h"
#include "fcp/client/http/curl/curl_api.h"
#include "fcp/client/http/curl/curl_header_parser.h"
#include "fcp/client/http/curl/curl_http_response.h"
#include "fcp/client/http/http_client_util.h"

namespace fcp::client::http::curl {
namespace {
// A type check for the macro.
inline CURLcode AsCode(CURLcode code) { return code; }
/**
 * Macro which allows to check for a status code and return from the
 * current method if not OK. Example:
 *
 *     Status DoSomething() {
 *       CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(...));
 *     }
 */
#define CURL_RETURN_IF_ERROR(expr)                        \
  do {                                                    \
    CURLcode __code = AsCode(expr);                       \
    if (__code != CURLE_OK) {                             \
      FCP_LOG(ERROR) << "Easy handle failed with "        \
                     << CurlEasyHandle::StrError(__code); \
      return (__code);                                    \
    }                                                     \
  } while (false)
}  // namespace

size_t CurlHttpRequestHandle::HeaderCallback(char* buffer, size_t size,
                                             size_t n_items, void* user_data) {
  auto self = static_cast<CurlHttpRequestHandle*>(user_data);
  std::string str_header(static_cast<char*>(buffer), size * n_items);

  self->header_parser_.ParseHeader(str_header);
  if (!self->header_parser_.IsLastHeader()) {
    return size * n_items;
  }

  self->response_ =
      std::make_unique<CurlHttpResponse>(self->header_parser_.GetStatusCode(),
                                         self->header_parser_.GetHeaderList());

  FCP_CHECK(self->callback_ != nullptr);
  absl::Status status =
      self->callback_->OnResponseStarted(*self->request_, *self->response_);

  if (!status.ok()) {
    FCP_LOG(ERROR) << "Called OnResponseStarted. Received status: " << status;
    self->callback_->OnResponseError(*self->request_, status);
  }

  return size * n_items;
}

size_t CurlHttpRequestHandle::DownloadCallback(void* body, size_t size,
                                               size_t nmemb, void* user_data) {
  auto self = static_cast<CurlHttpRequestHandle*>(user_data);
  absl::string_view str_body(static_cast<char*>(body), size * nmemb);

  absl::Status status = self->callback_->OnResponseBody(
      *self->request_, *self->response_, str_body);

  if (!status.ok()) {
    FCP_LOG(ERROR) << "Called OnResponseBody. Received status: " << status;
    self->callback_->OnResponseBodyError(*self->request_, *self->response_,
                                         status);
  }

  return size * nmemb;
}

size_t CurlHttpRequestHandle::UploadCallback(char* buffer, size_t size,
                                             size_t num, void* user_data) {
  auto self = static_cast<CurlHttpRequestHandle*>(user_data);
  size_t buffer_size = size * num;

  absl::StatusOr<int64_t> read_size =
      self->request_->ReadBody(buffer, buffer_size);
  if (read_size.ok()) {
    return read_size.value();
  } else if (read_size.status().code() == absl::StatusCode::kOutOfRange) {
    return 0;
  }
  return CURL_READFUNC_ABORT;
}

size_t CurlHttpRequestHandle::ProgressCallback(void* user_data,
                                               curl_off_t dltotal,
                                               curl_off_t dlnow,
                                               curl_off_t ultotal,
                                               curl_off_t ulnow) {
  auto self = static_cast<CurlHttpRequestHandle*>(user_data);
  absl::MutexLock lock(&self->mutex_);
  // Abort is any number except zero.
  return (self->is_cancelled_) ? 1 : 0;
}

CurlHttpRequestHandle::CurlHttpRequestHandle(
    std::unique_ptr<HttpRequest> request,
    std::unique_ptr<CurlEasyHandle> easy_handle,
    const std::string& test_cert_path)
    : request_(std::move(request)),
      response_(nullptr),
      easy_handle_(std::move(easy_handle)),
      callback_(nullptr),
      is_being_performed_(false),
      is_completed_(false),
      is_cancelled_(false),
      header_list_(nullptr) {
  FCP_CHECK(request_ != nullptr);
  FCP_CHECK(easy_handle_ != nullptr);

  CURLcode code = InitializeConnection(test_cert_path);
  if (code != CURLE_OK) {
    FCP_LOG(ERROR) << "easy_handle initialization failed with code "
                   << CurlEasyHandle::StrError(code);
    FCP_LOG(ERROR) << error_buffer_;
    callback_->OnResponseError(*request_, absl::InternalError(error_buffer_));
    return;
  }
}

CurlHttpRequestHandle::~CurlHttpRequestHandle() {
  curl_slist_free_all(header_list_);
}

void CurlHttpRequestHandle::Cancel() {
  absl::MutexLock lock(&mutex_);

  if (callback_ == nullptr || is_cancelled_ || is_completed_) {
    return;
  }
  if (response_ != nullptr) {
    callback_->OnResponseBodyError(*request_, *response_,
                                   absl::CancelledError());
  } else {
    callback_->OnResponseError(*request_, absl::CancelledError());
  }
  is_cancelled_ = true;
}

void CurlHttpRequestHandle::MarkAsCompleted() {
  absl::MutexLock lock(&mutex_);

  FCP_CHECK(callback_ != nullptr);
  if (!is_cancelled_ && !is_completed_) {
    if (response_ != nullptr) {
      callback_->OnResponseCompleted(*request_, *response_);
    } else {
      callback_->OnResponseError(*request_,
                                 absl::InternalError("response_ is nullptr"));
    }
  }
  is_completed_ = true;
}

absl::Status CurlHttpRequestHandle::AddToMulti(CurlMultiHandle* multi_handle,
                                               HttpRequestCallback* callback) {
  absl::MutexLock lock(&mutex_);

  FCP_CHECK(callback != nullptr);
  FCP_CHECK(multi_handle != nullptr);

  if (is_cancelled_) {
    callback->OnResponseError(*request_, absl::CancelledError());
    return absl::CancelledError();
  } else if (is_being_performed_ || is_completed_) {
    return absl::ResourceExhaustedError(
        "The handle was previously passed to another PerformRequests call.");
  }

  is_being_performed_ = true;
  callback_ = callback;

  CURLMcode code = multi_handle->AddEasyHandle(easy_handle_.get());
  if (code != CURLM_OK) {
    FCP_LOG(ERROR) << "AddEasyHandle failed with code " << code;
    FCP_LOG(ERROR) << error_buffer_;
    callback_->OnResponseError(*request_, absl::InternalError(error_buffer_));
    return absl::InternalError(error_buffer_);
  }

  return absl::OkStatus();
}

void CurlHttpRequestHandle::RemoveFromMulti(CurlMultiHandle* multi_handle) {
  absl::MutexLock lock(&mutex_);

  FCP_CHECK(multi_handle != nullptr);
  CURLMcode code = multi_handle->RemoveEasyHandle(easy_handle_.get());
  if (code != CURLM_OK) {
    FCP_LOG(ERROR) << "RemoveEasyHandle failed with code "
                   << CurlMultiHandle::StrError(code);
    FCP_LOG(ERROR) << error_buffer_;
  }
}

HttpRequestHandle::SentReceivedBytes
CurlHttpRequestHandle::TotalSentReceivedBytes() const {
  absl::MutexLock lock(&mutex_);
  curl_off_t total_sent_bytes = 0;
  CURLcode code =
      easy_handle_->GetInfo(CURLINFO_SIZE_UPLOAD_T, &total_sent_bytes);
  if (code != CURLE_OK) {
    FCP_LOG(ERROR) << "TotalSentBytes failed with code " << code;
    FCP_LOG(ERROR) << error_buffer_;
  }
  curl_off_t total_received_bytes = 0;
  code = easy_handle_->GetInfo(CURLINFO_SIZE_DOWNLOAD_T, &total_received_bytes);
  if (code != CURLE_OK) {
    FCP_LOG(ERROR) << "TotalReceivedBytes failed with code " << code;
    FCP_LOG(ERROR) << error_buffer_;
  }
  return {.sent_bytes = total_sent_bytes,
          .received_bytes = total_received_bytes};
}

CURLcode CurlHttpRequestHandle::InitializeConnection(
    const std::string& test_cert_path) {
  error_buffer_[0] = 0;
  // Needed to read an error message.
  CURL_RETURN_IF_ERROR(
      easy_handle_->SetOpt(CURLOPT_ERRORBUFFER, error_buffer_));

  // Skip all signal handling because is not thread-safe.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_NOSIGNAL, 1L));

  CURL_RETURN_IF_ERROR(
      easy_handle_->SetOpt(CURLOPT_URL, std::string(request_->uri())));

  // Forces curl to follow redirects.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_FOLLOWLOCATION, 1L));

  // Suppresses headers added by a proxy.
  CURL_RETURN_IF_ERROR(
      easy_handle_->SetOpt(CURLOPT_SUPPRESS_CONNECT_HEADERS, 1L));

  // Force curl to verify the ssl connection.
  CURL_RETURN_IF_ERROR(
      test_cert_path.empty()
          ? easy_handle_->SetOpt(CURLOPT_CAINFO, nullptr)
          : easy_handle_->SetOpt(CURLOPT_CAINFO, test_cert_path));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_SSL_VERIFYPEER, 2L));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_SSL_VERIFYHOST, 1L));

  // Force curl to never timeout.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_TIMEOUT_MS,
                                            std::numeric_limits<int>::max()));

  // Called when a response header received.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(
      CURLOPT_HEADERFUNCTION, &CurlHttpRequestHandle::HeaderCallback));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_HEADERDATA, this));

  // Called when a response body received.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(
      CURLOPT_WRITEFUNCTION, &CurlHttpRequestHandle::DownloadCallback));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_WRITEDATA, this));

  // Called to send a request body
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(
      CURLOPT_READFUNCTION, &CurlHttpRequestHandle::UploadCallback));

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_READDATA, this));

  // Called periodically. We use it to check whether the request is cancelled.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(
      CURLOPT_XFERINFOFUNCTION, &CurlHttpRequestHandle::ProgressCallback));
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_XFERINFODATA, this));
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_NOPROGRESS, 0L));

  // Private storage. Used by a multi-handle.
  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_PRIVATE, this));

  switch (request_->method()) {
    case HttpRequest::Method::kGet:
      CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_HTTPGET, 1L));
      break;
    case HttpRequest::Method::kHead:
      CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_NOBODY, 1L));
      break;
    case HttpRequest::Method::kPost:
      CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_POST, 1L));
      // Forces curl to use the callback.
      CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_POSTFIELDS, nullptr));
      break;
    case HttpRequest::Method::kPut:
    case HttpRequest::Method::kPatch:
    case HttpRequest::Method::kDelete:
      // TODO(team): Implement the requests when they are needed
      FCP_LOG(ERROR) << "Unsupported request type";
      return CURLE_UNSUPPORTED_PROTOCOL;
  }

  return InitializeHeaders(request_->extra_headers());
}

CURLcode CurlHttpRequestHandle::InitializeHeaders(
    const HeaderList& extra_headers) {
  // If no "Accept-Encoding" request header is explicitly specified
  // advertise an "Accept-Encoding: gzip" else leave decoded.
  std::optional<std::string> accept_encoding =
      FindHeader(request_->extra_headers(), kAcceptEncodingHdr);
  if (!accept_encoding.has_value()) {
    // Libcurl is responsible for the encoding.
    CURL_RETURN_IF_ERROR(
        easy_handle_->SetOpt(CURLOPT_ACCEPT_ENCODING, kGzipEncodingHdrValue));
    header_parser_.UseCurlEncoding();
  } else {
    // The caller is responsible for the encoding.
    CURL_RETURN_IF_ERROR(
        easy_handle_->SetOpt(CURLOPT_ACCEPT_ENCODING, nullptr));
  }

  for (auto& [key, value] : extra_headers) {
    if (absl::EqualsIgnoreCase(key, kAcceptEncodingHdr)) {
      continue;
    } else if (absl::EqualsIgnoreCase(key, kContentLengthHdr)) {
      // For post less than 2GB
      CURL_RETURN_IF_ERROR(
          easy_handle_->SetOpt(CURLOPT_POSTFIELDSIZE, std::stol(value)));
    } else {
      curl_slist* tmp = curl_slist_append(
          header_list_, absl::StrCat(key, ": ", value).c_str());
      FCP_CHECK(tmp != nullptr);
      header_list_ = tmp;
    }
  }

  CURL_RETURN_IF_ERROR(easy_handle_->SetOpt(CURLOPT_HTTPHEADER, header_list_));
  return CURLE_OK;
}
}  // namespace fcp::client::http::curl
<|endoftext|>


<commit_before>#include "DiagnosticStream.h"
#include "BitFunnel/Utilities/Factories.h"

namespace BitFunnel
{
    std::unique_ptr<IDiagnosticStream> Factories::CreateDiagnosticStream(std::ostream& stream)
    {
        return std::unique_ptr<IDiagnosticStream>(new DiagnosticStream(stream));
    }

    DiagnosticStream::DiagnosticStream(std::ostream& stream)
        : m_stream(stream)
    {
    }

    void DiagnosticStream::Enable(char const * diagnostic)
    {
        // TODO: REVIEW: check for duplicates?
        m_enabled.push_back(diagnostic);
    }

    void DiagnosticStream::Disable(char const * diagnostic)
    {
        // TODO: REVIEW: check for mismatch?
        for (unsigned i = 0 ; i < m_enabled.size(); ++i)
        {
            if (m_enabled[i].compare(diagnostic) == 0)
            {
                m_enabled.erase(m_enabled.begin() + i);

                // TODO: REVIEW: Assuming there is only one to remove.
                break;
            }
        }
    }

    // Returns true if text starts with prefix.
    bool StartsWith(char const * text, std::string const & prefix)
    {
        for (unsigned i = 0 ; i < prefix.size(); ++i)
        {
            if (*text != prefix[i])
            {
                return false;
            }
            ++text;
        }
        return true;
    }

    bool DiagnosticStream::IsEnabled(char const * diagnostic) const
    {
        for (unsigned i = 0; i < m_enabled.size(); ++i)
        {
            if (StartsWith(diagnostic, m_enabled[i]))
            {
                return true;
            }
        }
        return false;
    }

    std::ostream& DiagnosticStream::GetStream()
    {
        return m_stream;
    }
}
<commit_msg>Add missing license.<commit_after>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "DiagnosticStream.h"
#include "BitFunnel/Utilities/Factories.h"

namespace BitFunnel
{
    std::unique_ptr<IDiagnosticStream> Factories::CreateDiagnosticStream(std::ostream& stream)
    {
        return std::unique_ptr<IDiagnosticStream>(new DiagnosticStream(stream));
    }

    DiagnosticStream::DiagnosticStream(std::ostream& stream)
        : m_stream(stream)
    {
    }

    void DiagnosticStream::Enable(char const * diagnostic)
    {
        // TODO: REVIEW: check for duplicates?
        m_enabled.push_back(diagnostic);
    }

    void DiagnosticStream::Disable(char const * diagnostic)
    {
        // TODO: REVIEW: check for mismatch?
        for (unsigned i = 0 ; i < m_enabled.size(); ++i)
        {
            if (m_enabled[i].compare(diagnostic) == 0)
            {
                m_enabled.erase(m_enabled.begin() + i);

                // TODO: REVIEW: Assuming there is only one to remove.
                break;
            }
        }
    }

    // Returns true if text starts with prefix.
    bool StartsWith(char const * text, std::string const & prefix)
    {
        for (unsigned i = 0 ; i < prefix.size(); ++i)
        {
            if (*text != prefix[i])
            {
                return false;
            }
            ++text;
        }
        return true;
    }

    bool DiagnosticStream::IsEnabled(char const * diagnostic) const
    {
        for (unsigned i = 0; i < m_enabled.size(); ++i)
        {
            if (StartsWith(diagnostic, m_enabled[i]))
            {
                return true;
            }
        }
        return false;
    }

    std::ostream& DiagnosticStream::GetStream()
    {
        return m_stream;
    }
}
<|endoftext|>


<commit_before>// Native.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "Native.h"
#include <cstdlib>

template <typename T>
inline T clamp(T x, T min, T max)
{
	if (x < min) return min;
	if (x > max) return max;
	return x;
}

template <typename T>
inline T randf() { return (T)rand() / (T)RAND_MAX; }

template <typename T>
inline T dither(T x)
{
	return x + randf<T>();
}

template <int Bits, typename Fixed, typename Float>
void FixedToFloat(const Fixed * In, Float * Out, int Count)
{
	static const Float Max = (Float)((1UL << (Bits - 1)) - 1);

	for (int i = 0; i < Count; ++i)
		Out[i] = (Float)In[i] * (Float)(1.0 / Max);
}

template <int Bits, typename Float, typename Fixed>
void FloatToFixed(const Float * In, Fixed * Out, int Count)
{
	static const Float Max = (Float)((1UL << (Bits - 1)) - 1);

	for (int i = 0; i < Count; ++i)
		Out[i] = (Fixed)(clamp(dither(In[i] * Max), -Max, Max));
}

template <typename Float1, typename Float2>
void FloatToFloat(const Float1 * In, Float2 * Out, int Count)
{
	for (int i = 0; i < Count; ++i)
		Out[i] = (Float2)In[i];
}

extern "C" NATIVE_API void LEi16ToLEf32(const short * In, float * Out, int Count) { FixedToFloat<16>(In, Out, Count); }
extern "C" NATIVE_API void LEi16ToLEf64(const short * In, double * Out, int Count) { FixedToFloat<16>(In, Out, Count); }
extern "C" NATIVE_API void LEi32ToLEf32(const int * In, float * Out, int Count) { FixedToFloat<32>(In, Out, Count); }
extern "C" NATIVE_API void LEi32ToLEf64(const int * In, double * Out, int Count) { FixedToFloat<32>(In, Out, Count); }
extern "C" NATIVE_API void LEf32ToLEf64(const float * In, double * Out, int Count) { FloatToFloat(In, Out, Count); }

extern "C" NATIVE_API void LEf32ToLEi16(const float * In, short * Out, int Count) { FloatToFixed<16>(In, Out, Count); }
extern "C" NATIVE_API void LEf64ToLEi16(const double * In, short * Out, int Count) { FloatToFixed<16>(In, Out, Count); }
extern "C" NATIVE_API void LEf32ToLEi32(const float * In, short * Out, int Count) { FloatToFixed<32>(In, Out, Count); }
extern "C" NATIVE_API void LEf64ToLEi32(const double * In, short * Out, int Count) { FloatToFixed<32>(In, Out, Count); }
extern "C" NATIVE_API void LEf64ToLEf32(const double * In, float * Out, int Count) { FloatToFloat(In, Out, Count); }

                //case AsioWrapper.SampleType.Int16MSB:
                //case AsioWrapper.SampleType.Int24MSB:
                //case AsioWrapper.SampleType.Int32MSB:
                //case AsioWrapper.SampleType.Float32MSB:
                //case AsioWrapper.SampleType.Float64MSB:
                //case AsioWrapper.SampleType.Int32MSB16:
                //case AsioWrapper.SampleType.Int32MSB18:
                //case AsioWrapper.SampleType.Int32MSB20:
                //case AsioWrapper.SampleType.Int32MSB24:
                //case AsioWrapper.SampleType.Int16LSB:
                //case AsioWrapper.SampleType.Int24LSB:
                //case AsioWrapper.SampleType.Int32LSB:
                //case AsioWrapper.SampleType.Float32LSB:
                //case AsioWrapper.SampleType.Float64LSB:
                //case AsioWrapper.SampleType.Int32LSB16:
                //case AsioWrapper.SampleType.Int32LSB18:
                //case AsioWrapper.SampleType.Int32LSB20:
                //case AsioWrapper.SampleType.Int32LSB24:
                //case AsioWrapper.SampleType.DSDInt8LSB1:
                //case AsioWrapper.SampleType.DSDInt8MSB1:
                //case AsioWrapper.SampleType.DSDInt8NER8:<commit_msg>Fixed Toi32 functions<commit_after>// Native.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "Native.h"
#include <cstdlib>

template <typename T>
inline T clamp(T x, T min, T max)
{
	if (x < min) return min;
	if (x > max) return max;
	return x;
}

template <typename T>
inline T randf() { return (T)rand() / (T)RAND_MAX; }

template <typename T>
inline T dither(T x)
{
	return x + randf<T>();
}

template <int Bits, typename Fixed, typename Float>
void FixedToFloat(const Fixed * In, Float * Out, int Count)
{
	static const Float Max = (Float)((1UL << (Bits - 1)) - 1);

	for (int i = 0; i < Count; ++i)
		Out[i] = (Float)In[i] * (Float)(1.0 / Max);
}

template <int Bits, typename Float, typename Fixed>
void FloatToFixed(const Float * In, Fixed * Out, int Count)
{
	static const Float Max = (Float)((1UL << (Bits - 1)) - 1);

	for (int i = 0; i < Count; ++i)
		Out[i] = (Fixed)(clamp(dither(In[i] * Max), -Max, Max));
}

template <typename Float1, typename Float2>
void FloatToFloat(const Float1 * In, Float2 * Out, int Count)
{
	for (int i = 0; i < Count; ++i)
		Out[i] = (Float2)In[i];
}

extern "C" NATIVE_API void LEi16ToLEf32(const short * In, float * Out, int Count) { FixedToFloat<16>(In, Out, Count); }
extern "C" NATIVE_API void LEi16ToLEf64(const short * In, double * Out, int Count) { FixedToFloat<16>(In, Out, Count); }
extern "C" NATIVE_API void LEi32ToLEf32(const int * In, float * Out, int Count) { FixedToFloat<32>(In, Out, Count); }
extern "C" NATIVE_API void LEi32ToLEf64(const int * In, double * Out, int Count) { FixedToFloat<32>(In, Out, Count); }
extern "C" NATIVE_API void LEf32ToLEf64(const float * In, double * Out, int Count) { FloatToFloat(In, Out, Count); }

extern "C" NATIVE_API void LEf32ToLEi16(const float * In, short * Out, int Count) { FloatToFixed<16>(In, Out, Count); }
extern "C" NATIVE_API void LEf64ToLEi16(const double * In, short * Out, int Count) { FloatToFixed<16>(In, Out, Count); }
extern "C" NATIVE_API void LEf32ToLEi32(const float * In, int * Out, int Count) { FloatToFixed<32>(In, Out, Count); }
extern "C" NATIVE_API void LEf64ToLEi32(const double * In, int * Out, int Count) { FloatToFixed<32>(In, Out, Count); }
extern "C" NATIVE_API void LEf64ToLEf32(const double * In, float * Out, int Count) { FloatToFloat(In, Out, Count); }

                //case AsioWrapper.SampleType.Int16MSB:
                //case AsioWrapper.SampleType.Int24MSB:
                //case AsioWrapper.SampleType.Int32MSB:
                //case AsioWrapper.SampleType.Float32MSB:
                //case AsioWrapper.SampleType.Float64MSB:
                //case AsioWrapper.SampleType.Int32MSB16:
                //case AsioWrapper.SampleType.Int32MSB18:
                //case AsioWrapper.SampleType.Int32MSB20:
                //case AsioWrapper.SampleType.Int32MSB24:
                //case AsioWrapper.SampleType.Int16LSB:
                //case AsioWrapper.SampleType.Int24LSB:
                //case AsioWrapper.SampleType.Int32LSB:
                //case AsioWrapper.SampleType.Float32LSB:
                //case AsioWrapper.SampleType.Float64LSB:
                //case AsioWrapper.SampleType.Int32LSB16:
                //case AsioWrapper.SampleType.Int32LSB18:
                //case AsioWrapper.SampleType.Int32LSB20:
                //case AsioWrapper.SampleType.Int32LSB24:
                //case AsioWrapper.SampleType.DSDInt8LSB1:
                //case AsioWrapper.SampleType.DSDInt8MSB1:
                //case AsioWrapper.SampleType.DSDInt8NER8:<|endoftext|>


<commit_before>/**
* @file Main.cpp
*/
#include "GLFWEW.h"
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <vector>

/// _f[^^.
struct Vertex
{
  glm::vec3 position; ///< W.
  glm::vec4 color; ///< F.
  glm::vec2 texCoord; ///< eNX`W.
};

/// _f[^.
const Vertex vertices[] = {
  { {-0.5f, -0.3f, 0.5f}, {0.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f} },
  { { 0.3f, -0.3f, 0.5f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.3f,  0.5f, 0.5f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f} },
  { {-0.5f,  0.5f, 0.5f}, {0.0f, 0.0f, 1.0f, 1.0f}, {0.0f, 1.0f} },

  { {-0.3f,  0.3f, 0.1f}, {0.0f, 0.0f, 1.0f, 1.0f}, {0.0f, 1.0f} },
  { {-0.3f, -0.5f, 0.1f}, {0.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f} },
  { { 0.5f, -0.5f, 0.1f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.5f, -0.5f, 0.1f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.5f,  0.3f, 0.1f}, {1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 1.0f} },
  { {-0.3f,  0.3f, 0.1f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 1.0f} },
};

/// CfbNXf[^.
const GLuint indices[] = {
  0, 1, 2, 2, 3, 0,
  4, 5, 6, 7, 8, 9,
};

/// _VF[_.
static const char* vsCode =
"#version 410 \n"
"layout(location=0) in vec3 vPosition;"
"layout(location=1) in vec4 vColor;"
"layout(location=0) out vec4 outColor;"
"uniform mat4x4 matMVP;"
"void main() {"
"  outColor = vColor;"
"  gl_Position = matMVP * vec4(vPosition, 1.0);"
"}";

/// tOgVF[_.
static const char* fsCode =
"#version 410 \n"
"layout(location=0) in vec4 inColor;"
"out vec4 fragColor;"
"void main() {"
"  fragColor = inColor;"
"}";

/**
* Vertex Buffer Object쐬.
*
* @param size _f[^̃TCY.
* @param data _f[^ւ̃|C^.
*
* @return 쐬VBO.
*/
GLuint CreateVBO(GLsizeiptr size, const GLvoid* data)
{
  GLuint vbo = 0;
  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  return vbo;
}

/**
* Index Buffer Object쐬.
*
* @param size CfbNXf[^̃TCY.
* @param data CfbNXf[^ւ̃|C^.
*
* @return 쐬IBO.
*/
GLuint CreateIBO(GLsizeiptr size, const GLvoid* data)
{
  GLuint ibo = 0;
  glGenBuffers(1, &ibo);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  return ibo;
}

/**
* _Agr[gݒ肷.
*
* @param index _Agr[g̃CfbNX.
* @param cls   _f[^^.
* @param mbr   _Agr[gɐݒ肷cls̃oϐ.
*/
#define SetVertexAttribPointer(index, cls, mbr) SetVertexAttribPointerI( \
  index, \
  sizeof(cls::mbr) / sizeof(float), \
  sizeof(cls), \
  reinterpret_cast<GLvoid*>(offsetof(cls, mbr)))

void SetVertexAttribPointerI(GLuint index, GLint size, GLsizei stride, const GLvoid* pointer)
{
  glEnableVertexAttribArray(index);
  glVertexAttribPointer(index, size, GL_FLOAT, GL_FALSE, stride, pointer);
}

/**
* Vertex Array Object쐬.
*
* @param vbo VAOɊ֘AtVBO.
* @param ibo VAOɊ֘AtIBO.
*
* @return 쐬VAO.
*/
GLuint CreateVAO(GLuint vbo, GLuint ibo)
{
  GLuint vao = 0;
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  SetVertexAttribPointer(0, Vertex, position);
  SetVertexAttribPointer(1, Vertex, color);
  glBindVertexArray(0);
  glDeleteBuffers(1, &vbo);
  glDeleteBuffers(1, &ibo);
  return vao;
}

/**
* VF[_R[hRpC.
*
* @param type VF[_̎.
* @param string VF[_R[hւ̃|C^.
*
* @return 쐬VF[_IuWFNg.
*/
GLuint CompileShader(GLenum type, const GLchar* string)
{
  GLuint shader = glCreateShader(type);
  glShaderSource(shader, 1, &string, nullptr);
  glCompileShader(shader);
  GLint compiled = 0;
  glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
  if (!compiled) {
    GLint infoLen = 0;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
    if (infoLen) {
      std::vector<char> buf;
      buf.resize(infoLen);
      if (static_cast<int>(buf.size()) >= infoLen) {
        glGetShaderInfoLog(shader, infoLen, NULL, buf.data());
        std::cerr << "ERROR: VF[_̃RpCɎsn" << buf.data() << std::endl;
      }
    }
    glDeleteShader(shader);
    return 0;
  }
  return shader;
}

/**
* vOIuWFNg쐬.
*
* @param vsCode _VF[_R[hւ̃|C^.
* @param fsCode tOgVF[_R[hւ̃|C^.
*
* @return 쐬vOIuWFNg.
*/
GLuint CreateShaderProgram(const GLchar* vsCode, const GLchar* fsCode)
{
  GLuint vs = CompileShader(GL_VERTEX_SHADER, vsCode);
  GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsCode);
  if (!vs || !fs) {
    return 0;
  }
  GLuint program = glCreateProgram();
  glAttachShader(program, fs);
  glDeleteShader(fs);
  glAttachShader(program, vs);
  glDeleteShader(vs);
  glLinkProgram(program);
  GLint linkStatus = GL_FALSE;
  glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
  if (linkStatus != GL_TRUE) {
    GLint infoLen = 0;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
    if (infoLen) {
      std::vector<char> buf;
      buf.resize(infoLen);
      if (static_cast<int>(buf.size()) >= infoLen) {
        glGetProgramInfoLog(program, infoLen, NULL, buf.data());
        std::cerr << "ERROR: VF[_̃NɎsn"<< buf.data() << std::endl;
      }
    }
    glDeleteProgram(program);
    return 0;
  }
  return program;
}

/// Gg[|Cg.
int main()
{
  GLFWEW::Window& window = GLFWEW::Window::Instance();
  if (!window.Init(800, 600, "OpenGL Tutorial")) {
    return 1;
  }

  const GLuint vbo = CreateVBO(sizeof(vertices), vertices);
  const GLuint ibo = CreateIBO(sizeof(indices), indices);
  const GLuint vao = CreateVAO(vbo, ibo);
  const GLuint shaderProgram = CreateShaderProgram(vsCode, fsCode);
  if (!vbo || !ibo || !vao || !shaderProgram) {
    return 1;
  }

  glEnable(GL_DEPTH_TEST);

  // C[v.
  while (!window.ShouldClose()) {
    glClearColor(0.1f, 0.3f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // _]ړ.
    static float degree = 0.0f;
    degree += 0.1f;
    if (degree >= 360.0f) { degree -= 360.0f; }
    const glm::vec3 viewPos = glm::rotate(glm::mat4(), glm::radians(degree), glm::vec3(0, 1, 0)) * glm::vec4(2, 3, 3, 1);

    glUseProgram(shaderProgram);
    const GLint matMVPLoc = glGetUniformLocation(shaderProgram, "matMVP");
    if (matMVPLoc >= 0) {
      const glm::mat4x4 matProj =
        glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
      const glm::mat4x4 matView =
        glm::lookAt(viewPos, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
      const glm::mat4x4 matMVP = matProj * matView;
      glUniformMatrix4fv(matMVPLoc, 1, GL_FALSE, &matMVP[0][0]);
    }
    glBindVertexArray(vao);
    glDrawElements(
      GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]),
      GL_UNSIGNED_INT, reinterpret_cast<const GLvoid*>(0));

    window.SwapBuffers();
  }

  glDeleteProgram(shaderProgram);
  glDeleteVertexArrays(1, &vao);

  return 0;
}<commit_msg>第04回6章まで実装.<commit_after>/**
* @file Main.cpp
*/
#include "GLFWEW.h"
#include "Texture.h"
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <vector>

/// _f[^^.
struct Vertex
{
  glm::vec3 position; ///< W.
  glm::vec4 color; ///< F.
  glm::vec2 texCoord; ///< eNX`W.
};

/// _f[^.
const Vertex vertices[] = {
  { {-0.5f, -0.3f, 0.5f}, {0.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f} },
  { { 0.3f, -0.3f, 0.5f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.3f,  0.5f, 0.5f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f} },
  { {-0.5f,  0.5f, 0.5f}, {0.0f, 0.0f, 1.0f, 1.0f}, {0.0f, 1.0f} },

  { {-0.3f,  0.3f, 0.1f}, {0.0f, 0.0f, 1.0f, 1.0f}, {0.0f, 1.0f} },
  { {-0.3f, -0.5f, 0.1f}, {0.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f} },
  { { 0.5f, -0.5f, 0.1f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.5f, -0.5f, 0.1f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.5f,  0.3f, 0.1f}, {1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 1.0f} },
  { {-0.3f,  0.3f, 0.1f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 1.0f} },
};

/// CfbNXf[^.
const GLuint indices[] = {
  0, 1, 2, 2, 3, 0,
  4, 5, 6, 7, 8, 9,
};

/// _VF[_.
static const char* vsCode =
"#version 410 \n"
"layout(location=0) in vec3 vPosition;"
"layout(location=1) in vec4 vColor;"
"layout(location=2) in vec2 vTexCoord;"
"layout(location=0) out vec4 outColor;"
"layout(location=1) out vec2 outTexCoord;"
"uniform mat4x4 matMVP;"
"void main() {"
"  outColor = vColor;"
"  outTexCoord = vTexCoord;"
"  gl_Position = matMVP * vec4(vPosition, 1.0);"
"}";

/// tOgVF[_.
static const char* fsCode =
"#version 410 \n"
"layout(location=0) in vec4 inColor;"
"layout(location=1) in vec2 inTexCoord;"
"uniform sampler2D colorSampler;"
"out vec4 fragColor;"
"void main() {"
"  fragColor = inColor * texture(colorSampler, inTexCoord);"
"}";

/**
* Vertex Buffer Object쐬.
*
* @param size _f[^̃TCY.
* @param data _f[^ւ̃|C^.
*
* @return 쐬VBO.
*/
GLuint CreateVBO(GLsizeiptr size, const GLvoid* data)
{
  GLuint vbo = 0;
  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  return vbo;
}

/**
* Index Buffer Object쐬.
*
* @param size CfbNXf[^̃TCY.
* @param data CfbNXf[^ւ̃|C^.
*
* @return 쐬IBO.
*/
GLuint CreateIBO(GLsizeiptr size, const GLvoid* data)
{
  GLuint ibo = 0;
  glGenBuffers(1, &ibo);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  return ibo;
}

/**
* _Agr[gݒ肷.
*
* @param index _Agr[g̃CfbNX.
* @param cls   _f[^^.
* @param mbr   _Agr[gɐݒ肷cls̃oϐ.
*/
#define SetVertexAttribPointer(index, cls, mbr) SetVertexAttribPointerI( \
  index, \
  sizeof(cls::mbr) / sizeof(float), \
  sizeof(cls), \
  reinterpret_cast<GLvoid*>(offsetof(cls, mbr)))

void SetVertexAttribPointerI(GLuint index, GLint size, GLsizei stride, const GLvoid* pointer)
{
  glEnableVertexAttribArray(index);
  glVertexAttribPointer(index, size, GL_FLOAT, GL_FALSE, stride, pointer);
}

/**
* Vertex Array Object쐬.
*
* @param vbo VAOɊ֘AtVBO.
* @param ibo VAOɊ֘AtIBO.
*
* @return 쐬VAO.
*/
GLuint CreateVAO(GLuint vbo, GLuint ibo)
{
  GLuint vao = 0;
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  SetVertexAttribPointer(0, Vertex, position);
  SetVertexAttribPointer(1, Vertex, color);
  SetVertexAttribPointer(2, Vertex, texCoord);
  glBindVertexArray(0);
  glDeleteBuffers(1, &vbo);
  glDeleteBuffers(1, &ibo);
  return vao;
}

/**
* VF[_R[hRpC.
*
* @param type VF[_̎.
* @param string VF[_R[hւ̃|C^.
*
* @return 쐬VF[_IuWFNg.
*/
GLuint CompileShader(GLenum type, const GLchar* string)
{
  GLuint shader = glCreateShader(type);
  glShaderSource(shader, 1, &string, nullptr);
  glCompileShader(shader);
  GLint compiled = 0;
  glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
  if (!compiled) {
    GLint infoLen = 0;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
    if (infoLen) {
      std::vector<char> buf;
      buf.resize(infoLen);
      if (static_cast<int>(buf.size()) >= infoLen) {
        glGetShaderInfoLog(shader, infoLen, NULL, buf.data());
        std::cerr << "ERROR: VF[_̃RpCɎsn" << buf.data() << std::endl;
      }
    }
    glDeleteShader(shader);
    return 0;
  }
  return shader;
}

/**
* vOIuWFNg쐬.
*
* @param vsCode _VF[_R[hւ̃|C^.
* @param fsCode tOgVF[_R[hւ̃|C^.
*
* @return 쐬vOIuWFNg.
*/
GLuint CreateShaderProgram(const GLchar* vsCode, const GLchar* fsCode)
{
  GLuint vs = CompileShader(GL_VERTEX_SHADER, vsCode);
  GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsCode);
  if (!vs || !fs) {
    return 0;
  }
  GLuint program = glCreateProgram();
  glAttachShader(program, fs);
  glDeleteShader(fs);
  glAttachShader(program, vs);
  glDeleteShader(vs);
  glLinkProgram(program);
  GLint linkStatus = GL_FALSE;
  glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
  if (linkStatus != GL_TRUE) {
    GLint infoLen = 0;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
    if (infoLen) {
      std::vector<char> buf;
      buf.resize(infoLen);
      if (static_cast<int>(buf.size()) >= infoLen) {
        glGetProgramInfoLog(program, infoLen, NULL, buf.data());
        std::cerr << "ERROR: VF[_̃NɎsn"<< buf.data() << std::endl;
      }
    }
    glDeleteProgram(program);
    return 0;
  }
  return program;
}

/// Gg[|Cg.
int main()
{
  GLFWEW::Window& window = GLFWEW::Window::Instance();
  if (!window.Init(800, 600, "OpenGL Tutorial")) {
    return 1;
  }

  const GLuint vbo = CreateVBO(sizeof(vertices), vertices);
  const GLuint ibo = CreateIBO(sizeof(indices), indices);
  const GLuint vao = CreateVAO(vbo, ibo);
  const GLuint shaderProgram = CreateShaderProgram(vsCode, fsCode);
  if (!vbo || !ibo || !vao || !shaderProgram) {
    return 1;
  }

  /// eNX`f[^.
  static const uint32_t textureData[] = {
    0xffffffff, 0xffcccccc, 0xffffffff, 0xffcccccc, 0xffffffff,
    0xff888888, 0xffffffff, 0xff888888, 0xffffffff, 0xff888888,
    0xffffffff, 0xff444444, 0xffffffff, 0xff444444, 0xffffffff,
    0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000,
    0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff,
  };
  TexturePtr tex = Texture::Create(5, 5, GL_RGBA8, GL_RGBA, textureData);
  if (!tex) {
    return 1;
  }

  glEnable(GL_DEPTH_TEST);

  // C[v.
  while (!window.ShouldClose()) {
    glClearColor(0.1f, 0.3f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // _]ړ.
    static float degree = 0.0f;
    degree += 0.1f;
    if (degree >= 360.0f) { degree -= 360.0f; }
    const glm::vec3 viewPos = glm::rotate(glm::mat4(), glm::radians(degree), glm::vec3(0, 1, 0)) * glm::vec4(2, 3, 3, 1);

    glUseProgram(shaderProgram);
    const GLint matMVPLoc = glGetUniformLocation(shaderProgram, "matMVP");
    if (matMVPLoc >= 0) {
      const glm::mat4x4 matProj =
        glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
      const glm::mat4x4 matView =
        glm::lookAt(viewPos, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
      const glm::mat4x4 matMVP = matProj * matView;
      glUniformMatrix4fv(matMVPLoc, 1, GL_FALSE, &matMVP[0][0]);
    }
    const GLint colorSamplerLoc = glGetUniformLocation(shaderProgram, "colorSampler");
    if (colorSamplerLoc >= 0) {
      glUniform1i(colorSamplerLoc, 0);
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, tex->Id());
    }
    glBindVertexArray(vao);
    glDrawElements(
      GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]),
      GL_UNSIGNED_INT, reinterpret_cast<const GLvoid*>(0));

    window.SwapBuffers();
  }

  glDeleteProgram(shaderProgram);
  glDeleteVertexArrays(1, &vao);

  return 0;
}<|endoftext|>


<commit_before>#include "LinuxPerfData.h"
#include "SerializationMacros.h"
#include "Serialization.h"

void LinuxPerfData::Clear()
{
    m_CS.m_Data.clear();
    m_header = "";
    m_time = 0;
    m_tid = 0;
    m_numCallstacks = 0;
}

ORBIT_SERIALIZE( LinuxPerfData, 0 )
{
    ORBIT_NVP_VAL( 0, m_header );
    ORBIT_NVP_VAL( 0, m_tid );
    ORBIT_NVP_VAL( 0, m_time );
    ORBIT_NVP_VAL( 0, m_numCallstacks );
    ORBIT_NVP_VAL( 0, m_CS );
}<commit_msg>Clear callstack hash in LinuxPerfData.Clear() otherwise we end up assigning the same hash to all sampling events.<commit_after>#include "LinuxPerfData.h"
#include "SerializationMacros.h"
#include "Serialization.h"

void LinuxPerfData::Clear()
{
    m_CS.m_Data.clear();
    m_CS.m_Hash = 0;
    m_header = "";
    m_time = 0;
    m_tid = 0;
    m_numCallstacks = 0;
}

ORBIT_SERIALIZE( LinuxPerfData, 0 )
{
    ORBIT_NVP_VAL( 0, m_header );
    ORBIT_NVP_VAL( 0, m_tid );
    ORBIT_NVP_VAL( 0, m_time );
    ORBIT_NVP_VAL( 0, m_numCallstacks );
    ORBIT_NVP_VAL( 0, m_CS );
}<|endoftext|>


<commit_before>/*
 *  Copyright 2013 David Farrell
 *
 *  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 "ResourceManager.h"

#include "stdio.h"
#include "stdlib.h"

char * ResourceManager::Load(const char *path, long *len)
{
    char *buffer = NULL;
    long err = 0;

    // open binary file for reading
    FILE *fh = fopen(path, "rb");
    if(!fh)
    {
        fprintf(stderr, "fopen: error\n");
        return NULL;
    }

    // fseek to end
    err = fseek(fh, 0L, SEEK_END);
    if(err != 0)
    {
        fprintf(stderr, "fseek: error\n");
        return NULL;
    }

    // get file size
    *len = ftell(fh);
    if(*len == -1L)
    {
        fprintf(stderr, "ftell: error\n");
        return NULL;
    }

    // fseek to start
    err = fseek(fh, 0L, SEEK_SET);
    if(err != 0)
    {
        fprintf(stderr, "fseek: error\n");
        return NULL;
    }

    // allocate buffer
    buffer = (char *)malloc(*len);
    if(buffer == NULL)
    {
        fprintf(stderr, "malloc: error\n");
        return NULL;
    }

    // read into buffer
    err = fread(buffer, *len, 1, fh);
    if(err != 1)
    {
        fprintf(stderr, "fread: error\n");
        return NULL;
    }

    // close file
    err = fclose(fh);
    if(err == EOF) fprintf(stderr, "fclose: error\n");

    return buffer;
}
<commit_msg>Added more useful fopen error message.<commit_after>/*
 *  Copyright 2013 David Farrell
 *
 *  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 "ResourceManager.h"

#include "stdio.h"
#include "stdlib.h"

char * ResourceManager::Load(const char *path, long *len)
{
    char *buffer = NULL;
    long err = 0;

    // open binary file for reading
    FILE *fh = fopen(path, "rb");
    if(!fh)
    {
        fprintf(stderr, "fopen: error opening `%s`\n", path);
        return NULL;
    }

    // fseek to end
    err = fseek(fh, 0L, SEEK_END);
    if(err != 0)
    {
        fprintf(stderr, "fseek: error\n");
        return NULL;
    }

    // get file size
    *len = ftell(fh);
    if(*len == -1L)
    {
        fprintf(stderr, "ftell: error\n");
        return NULL;
    }

    // fseek to start
    err = fseek(fh, 0L, SEEK_SET);
    if(err != 0)
    {
        fprintf(stderr, "fseek: error\n");
        return NULL;
    }

    // allocate buffer
    buffer = (char *)malloc(*len);
    if(buffer == NULL)
    {
        fprintf(stderr, "malloc: error\n");
        return NULL;
    }

    // read into buffer
    err = fread(buffer, *len, 1, fh);
    if(err != 1)
    {
        fprintf(stderr, "fread: error\n");
        return NULL;
    }

    // close file
    err = fclose(fh);
    if(err == EOF) fprintf(stderr, "fclose: error\n");

    return buffer;
}
<|endoftext|>


<commit_before>//===- examples/Tooling/RemoveCStrCalls.cpp - Redundant c_str call removal ===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements a tool that prints replacements that remove redundant
//  calls of c_str() on strings.
//
//  Usage:
//  remove-cstr-calls <cmake-output-dir> <file1> <file2> ...
//
//  Where <cmake-output-dir> is a CMake build directory in which a file named
//  compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
//  CMake to get this output).
//
//  <file1> ... specify the paths of files in the CMake source tree. This path
//  is looked up in the compile command database. If the path of a file is
//  absolute, it needs to point into CMake's source tree. If the path is
//  relative, the current working directory needs to be in the CMake source
//  tree and the file must be in a subdirectory of the current working
//  directory. "./" prefixes in the relative files will be automatically
//  removed, but the rest of a relative path must be a suffix of a path in
//  the compile command line database.
//
//  For example, to use remove-cstr-calls on all files in a subtree of the
//  source tree, use:
//
//    /path/in/subtree $ find . -name '*.cpp'|
//        xargs remove-cstr-calls /path/to/build
//
//===----------------------------------------------------------------------===//

#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"

using namespace clang;
using namespace clang::ast_matchers;
using namespace llvm;
using clang::tooling::newFrontendActionFactory;
using clang::tooling::Replacement;
using clang::tooling::CompilationDatabase;

// FIXME: Pull out helper methods in here into more fitting places.

// Returns the text that makes up 'node' in the source.
// Returns an empty string if the text cannot be found.
template <typename T>
static std::string getText(const SourceManager &SourceManager, const T &Node) {
  SourceLocation StartSpellingLocatino =
      SourceManager.getSpellingLoc(Node.getLocStart());
  SourceLocation EndSpellingLocation =
      SourceManager.getSpellingLoc(Node.getLocEnd());
  if (!StartSpellingLocatino.isValid() || !EndSpellingLocation.isValid()) {
    return std::string();
  }
  bool Invalid = true;
  const char *Text =
      SourceManager.getCharacterData(StartSpellingLocatino, &Invalid);
  if (Invalid) {
    return std::string();
  }
  std::pair<FileID, unsigned> Start =
      SourceManager.getDecomposedLoc(StartSpellingLocatino);
  std::pair<FileID, unsigned> End =
      SourceManager.getDecomposedLoc(Lexer::getLocForEndOfToken(
          EndSpellingLocation, 0, SourceManager, LangOptions()));
  if (Start.first != End.first) {
    // Start and end are in different files.
    return std::string();
  }
  if (End.second < Start.second) {
    // Shuffling text with macros may cause this.
    return std::string();
  }
  return std::string(Text, End.second - Start.second);
}

// Return true if expr needs to be put in parens when it is an
// argument of a prefix unary operator, e.g. when it is a binary or
// ternary operator syntactically.
static bool needParensAfterUnaryOperator(const Expr &ExprNode) {
  if (dyn_cast<clang::BinaryOperator>(&ExprNode) ||
      dyn_cast<clang::ConditionalOperator>(&ExprNode)) {
    return true;
  }
  if (const CXXOperatorCallExpr *op =
      dyn_cast<CXXOperatorCallExpr>(&ExprNode)) {
    return op->getNumArgs() == 2 &&
        op->getOperator() != OO_PlusPlus &&
        op->getOperator() != OO_MinusMinus &&
        op->getOperator() != OO_Call &&
        op->getOperator() != OO_Subscript;
  }
  return false;
}

// Format a pointer to an expression: prefix with '*' but simplify
// when it already begins with '&'.  Return empty string on failure.
static std::string formatDereference(const SourceManager &SourceManager,
                              const Expr &ExprNode) {
  if (const clang::UnaryOperator *Op =
      dyn_cast<clang::UnaryOperator>(&ExprNode)) {
    if (Op->getOpcode() == UO_AddrOf) {
      // Strip leading '&'.
      return getText(SourceManager, *Op->getSubExpr()->IgnoreParens());
    }
  }
  const std::string Text = getText(SourceManager, ExprNode);
  if (Text.empty()) return std::string();
  // Add leading '*'.
  if (needParensAfterUnaryOperator(ExprNode)) {
    return std::string("*(") + Text + ")";
  }
  return std::string("*") + Text;
}

namespace {
class FixCStrCall : public ast_matchers::MatchFinder::MatchCallback {
 public:
  FixCStrCall(tooling::Replacements *Replace)
      : Replace(Replace) {}

  virtual void run(const ast_matchers::MatchFinder::MatchResult &Result) {
    const CallExpr *Call =
        Result.Nodes.getStmtAs<CallExpr>("call");
    const Expr *Arg =
        Result.Nodes.getStmtAs<Expr>("arg");
    const bool Arrow =
        Result.Nodes.getStmtAs<MemberExpr>("member")->isArrow();
    // Replace the "call" node with the "arg" node, prefixed with '*'
    // if the call was using '->' rather than '.'.
    const std::string ArgText = Arrow ?
        formatDereference(*Result.SourceManager, *Arg) :
        getText(*Result.SourceManager, *Arg);
    if (ArgText.empty()) return;

    Replace->insert(Replacement(*Result.SourceManager, Call, ArgText));
  }

 private:
  tooling::Replacements *Replace;
};
} // end namespace

const char *StringConstructor =
    "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
    "::basic_string";

const char *StringCStrMethod =
    "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
    "::c_str";

cl::opt<std::string> BuildPath(
  cl::Positional,
  cl::desc("<build-path>"));

cl::list<std::string> SourcePaths(
  cl::Positional,
  cl::desc("<source0> [... <sourceN>]"),
  cl::OneOrMore);

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv);
  std::string ErrorMessage;
  llvm::OwningPtr<CompilationDatabase> Compilations(
    CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage));
  if (!Compilations)
    llvm::report_fatal_error(ErrorMessage);
  tooling::RefactoringTool Tool(*Compilations, SourcePaths);
  ast_matchers::MatchFinder Finder;
  FixCStrCall Callback(&Tool.getReplacements());
  Finder.addMatcher(
      constructorCall(
          hasDeclaration(method(hasName(StringConstructor))),
          argumentCountIs(2),
          // The first argument must have the form x.c_str() or p->c_str()
          // where the method is string::c_str().  We can use the copy
          // constructor of string instead (or the compiler might share
          // the string object).
          hasArgument(
              0,
              id("call", memberCall(
                  callee(id("member", memberExpression())),
                  callee(method(hasName(StringCStrMethod))),
                  on(id("arg", expression()))))),
          // The second argument is the alloc object which must not be
          // present explicitly.
          hasArgument(
              1,
              defaultArgument())),
      &Callback);
  Finder.addMatcher(
      constructorCall(
          // Implicit constructors of these classes are overloaded
          // wrt. string types and they internally make a StringRef
          // referring to the argument.  Passing a string directly to
          // them is preferred to passing a char pointer.
          hasDeclaration(method(anyOf(
              hasName("::llvm::StringRef::StringRef"),
              hasName("::llvm::Twine::Twine")))),
          argumentCountIs(1),
          // The only argument must have the form x.c_str() or p->c_str()
          // where the method is string::c_str().  StringRef also has
          // a constructor from string which is more efficient (avoids
          // strlen), so we can construct StringRef from the string
          // directly.
          hasArgument(
              0,
              id("call", memberCall(
                  callee(id("member", memberExpression())),
                  callee(method(hasName(StringCStrMethod))),
                  on(id("arg", expression())))))),
      &Callback);
  return Tool.run(newFrontendActionFactory(&Finder));
}

<commit_msg>Added code to let the user specify a compilation database on the command line<commit_after>//===- examples/Tooling/RemoveCStrCalls.cpp - Redundant c_str call removal ===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements a tool that prints replacements that remove redundant
//  calls of c_str() on strings.
//
//  Usage:
//  remove-cstr-calls <cmake-output-dir> <file1> <file2> ...
//
//  Where <cmake-output-dir> is a CMake build directory in which a file named
//  compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
//  CMake to get this output).
//
//  <file1> ... specify the paths of files in the CMake source tree. This path
//  is looked up in the compile command database. If the path of a file is
//  absolute, it needs to point into CMake's source tree. If the path is
//  relative, the current working directory needs to be in the CMake source
//  tree and the file must be in a subdirectory of the current working
//  directory. "./" prefixes in the relative files will be automatically
//  removed, but the rest of a relative path must be a suffix of a path in
//  the compile command line database.
//
//  For example, to use remove-cstr-calls on all files in a subtree of the
//  source tree, use:
//
//    /path/in/subtree $ find . -name '*.cpp'|
//        xargs remove-cstr-calls /path/to/build
//
//===----------------------------------------------------------------------===//

#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"

using namespace clang;
using namespace clang::ast_matchers;
using namespace llvm;
using clang::tooling::newFrontendActionFactory;
using clang::tooling::Replacement;
using clang::tooling::CompilationDatabase;

// FIXME: Pull out helper methods in here into more fitting places.

// Returns the text that makes up 'node' in the source.
// Returns an empty string if the text cannot be found.
template <typename T>
static std::string getText(const SourceManager &SourceManager, const T &Node) {
  SourceLocation StartSpellingLocatino =
      SourceManager.getSpellingLoc(Node.getLocStart());
  SourceLocation EndSpellingLocation =
      SourceManager.getSpellingLoc(Node.getLocEnd());
  if (!StartSpellingLocatino.isValid() || !EndSpellingLocation.isValid()) {
    return std::string();
  }
  bool Invalid = true;
  const char *Text =
      SourceManager.getCharacterData(StartSpellingLocatino, &Invalid);
  if (Invalid) {
    return std::string();
  }
  std::pair<FileID, unsigned> Start =
      SourceManager.getDecomposedLoc(StartSpellingLocatino);
  std::pair<FileID, unsigned> End =
      SourceManager.getDecomposedLoc(Lexer::getLocForEndOfToken(
          EndSpellingLocation, 0, SourceManager, LangOptions()));
  if (Start.first != End.first) {
    // Start and end are in different files.
    return std::string();
  }
  if (End.second < Start.second) {
    // Shuffling text with macros may cause this.
    return std::string();
  }
  return std::string(Text, End.second - Start.second);
}

// Return true if expr needs to be put in parens when it is an
// argument of a prefix unary operator, e.g. when it is a binary or
// ternary operator syntactically.
static bool needParensAfterUnaryOperator(const Expr &ExprNode) {
  if (dyn_cast<clang::BinaryOperator>(&ExprNode) ||
      dyn_cast<clang::ConditionalOperator>(&ExprNode)) {
    return true;
  }
  if (const CXXOperatorCallExpr *op =
      dyn_cast<CXXOperatorCallExpr>(&ExprNode)) {
    return op->getNumArgs() == 2 &&
        op->getOperator() != OO_PlusPlus &&
        op->getOperator() != OO_MinusMinus &&
        op->getOperator() != OO_Call &&
        op->getOperator() != OO_Subscript;
  }
  return false;
}

// Format a pointer to an expression: prefix with '*' but simplify
// when it already begins with '&'.  Return empty string on failure.
static std::string formatDereference(const SourceManager &SourceManager,
                              const Expr &ExprNode) {
  if (const clang::UnaryOperator *Op =
      dyn_cast<clang::UnaryOperator>(&ExprNode)) {
    if (Op->getOpcode() == UO_AddrOf) {
      // Strip leading '&'.
      return getText(SourceManager, *Op->getSubExpr()->IgnoreParens());
    }
  }
  const std::string Text = getText(SourceManager, ExprNode);
  if (Text.empty()) return std::string();
  // Add leading '*'.
  if (needParensAfterUnaryOperator(ExprNode)) {
    return std::string("*(") + Text + ")";
  }
  return std::string("*") + Text;
}

namespace {
class FixCStrCall : public ast_matchers::MatchFinder::MatchCallback {
 public:
  FixCStrCall(tooling::Replacements *Replace)
      : Replace(Replace) {}

  virtual void run(const ast_matchers::MatchFinder::MatchResult &Result) {
    const CallExpr *Call =
        Result.Nodes.getStmtAs<CallExpr>("call");
    const Expr *Arg =
        Result.Nodes.getStmtAs<Expr>("arg");
    const bool Arrow =
        Result.Nodes.getStmtAs<MemberExpr>("member")->isArrow();
    // Replace the "call" node with the "arg" node, prefixed with '*'
    // if the call was using '->' rather than '.'.
    const std::string ArgText = Arrow ?
        formatDereference(*Result.SourceManager, *Arg) :
        getText(*Result.SourceManager, *Arg);
    if (ArgText.empty()) return;

    Replace->insert(Replacement(*Result.SourceManager, Call, ArgText));
  }

 private:
  tooling::Replacements *Replace;
};
} // end namespace

const char *StringConstructor =
    "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
    "::basic_string";

const char *StringCStrMethod =
    "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
    "::c_str";

cl::opt<std::string> BuildPath(
  cl::Positional,
  cl::desc("<build-path>"));

cl::list<std::string> SourcePaths(
  cl::Positional,
  cl::desc("<source0> [... <sourceN>]"),
  cl::OneOrMore);

int main(int argc, const char **argv) {
  llvm::OwningPtr<CompilationDatabase> Compilations(
    tooling::FixedCompilationDatabase::loadFromCommandLine(argc, argv));
  cl::ParseCommandLineOptions(argc, argv);
  if (!Compilations) {
    std::string ErrorMessage;
    Compilations.reset(
           CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage));
    if (!Compilations)
      llvm::report_fatal_error(ErrorMessage);
    }
  tooling::RefactoringTool Tool(*Compilations, SourcePaths);
  ast_matchers::MatchFinder Finder;
  FixCStrCall Callback(&Tool.getReplacements());
  Finder.addMatcher(
      constructorCall(
          hasDeclaration(method(hasName(StringConstructor))),
          argumentCountIs(2),
          // The first argument must have the form x.c_str() or p->c_str()
          // where the method is string::c_str().  We can use the copy
          // constructor of string instead (or the compiler might share
          // the string object).
          hasArgument(
              0,
              id("call", memberCall(
                  callee(id("member", memberExpression())),
                  callee(method(hasName(StringCStrMethod))),
                  on(id("arg", expression()))))),
          // The second argument is the alloc object which must not be
          // present explicitly.
          hasArgument(
              1,
              defaultArgument())),
      &Callback);
  Finder.addMatcher(
      constructorCall(
          // Implicit constructors of these classes are overloaded
          // wrt. string types and they internally make a StringRef
          // referring to the argument.  Passing a string directly to
          // them is preferred to passing a char pointer.
          hasDeclaration(method(anyOf(
              hasName("::llvm::StringRef::StringRef"),
              hasName("::llvm::Twine::Twine")))),
          argumentCountIs(1),
          // The only argument must have the form x.c_str() or p->c_str()
          // where the method is string::c_str().  StringRef also has
          // a constructor from string which is more efficient (avoids
          // strlen), so we can construct StringRef from the string
          // directly.
          hasArgument(
              0,
              id("call", memberCall(
                  callee(id("member", memberExpression())),
                  callee(method(hasName(StringCStrMethod))),
                  on(id("arg", expression())))))),
      &Callback);
  return Tool.run(newFrontendActionFactory(&Finder));
}

<|endoftext|>