#include "fft.h"

//------------------------------------------------------------------------
// vectorProcess
//------------------------------------------------------------------------

// SEPARATOR_FOR_MAIN

#include "fft.h"
#include <stdlib.h>

#define N 32768
#define BIN_MAX_NUM 20

void fft(inout_float_t X_R_0[1024], inout_float_t X_R_1[1024],
         inout_float_t X_R_2[1024], inout_float_t X_R_3[1024],
         inout_float_t X_R_4[1024], inout_float_t X_R_5[1024],
         inout_float_t X_R_6[1024], inout_float_t X_R_7[1024],
         inout_float_t X_I_0[1024], inout_float_t X_I_1[1024],
         inout_float_t X_I_2[1024], inout_float_t X_I_3[1024],
         inout_float_t X_I_4[1024], inout_float_t X_I_5[1024],
         inout_float_t X_I_6[1024], inout_float_t X_I_7[1024],
         in_float_t cos_coefficients_table[512],
         in_float_t sin_coefficients_table[512]) {

loop_0:
  for (int i = 0; i < 2; i++)
    for (int stage = 1; stage <= 8; stage++) {
      int numBF = (1 << (stage - 1));
      for (int j = 0; j < numBF; j++) {
        float c = cos_coefficients_table[j << (8 - stage)];
        float s = sin_coefficients_table[j << (8 - stage)];
        int i_lower = j + numBF;
        float temp_R =
            X_R_0[i * 512 + i_lower] * c - X_I_0[i * 512 + i_lower] * s;
        float temp_I =
            X_I_0[i * 512 + i_lower] * c + X_R_0[i * 512 + i_lower] * s;
        X_R_0[i * 512 + i_lower] = X_R_0[i * 512 + j] - temp_R;
        X_I_0[i * 512 + i_lower] = X_I_0[i * 512 + j] - temp_I;
        X_R_0[i * 512 + j] = X_R_0[i * 512 + j] + temp_R;
        X_I_0[i * 512 + j] = X_I_0[i * 512 + j] + temp_I;
      }
    }

loop_1:
  for (int i = 0; i < 2; i++)
    for (int stage = 1; stage <= 8; stage++) {
      int numBF = (1 << (stage - 1));
      for (int j = 0; j < numBF; j++) {
        float c = cos_coefficients_table[j << (8 - stage)];
        float s = sin_coefficients_table[j << (8 - stage)];
        int i_lower = j + numBF;
        float temp_R =
            X_R_1[i * 512 + i_lower] * c - X_I_1[i * 512 + i_lower] * s;
        float temp_I =
            X_I_1[i * 512 + i_lower] * c + X_R_1[i * 512 + i_lower] * s;
        X_R_1[i * 512 + i_lower] = X_R_1[i * 512 + j] - temp_R;
        X_I_1[i * 512 + i_lower] = X_I_1[i * 512 + j] - temp_I;
        X_R_1[i * 512 + j] = X_R_1[i * 512 + j] + temp_R;
        X_I_1[i * 512 + j] = X_I_1[i * 512 + j] + temp_I;
      }
    }

loop_2:
  for (int i = 0; i < 2; i++)
    for (int stage = 1; stage <= 8; stage++) {
      int numBF = (1 << (stage - 1));
      for (int j = 0; j < numBF; j++) {
        float c = cos_coefficients_table[j << (8 - stage)];
        float s = sin_coefficients_table[j << (8 - stage)];
        int i_lower = j + numBF;
        float temp_R =
            X_R_2[i * 512 + i_lower] * c - X_I_2[i * 512 + i_lower] * s;
        float temp_I =
            X_I_2[i * 512 + i_lower] * c + X_R_2[i * 512 + i_lower] * s;
        X_R_2[i * 512 + i_lower] = X_R_2[i * 512 + j] - temp_R;
        X_I_2[i * 512 + i_lower] = X_I_2[i * 512 + j] - temp_I;
        X_R_2[i * 512 + j] = X_R_2[i * 512 + j] + temp_R;
        X_I_2[i * 512 + j] = X_I_2[i * 512 + j] + temp_I;
      }
    }

loop_3:
  for (int i = 0; i < 2; i++)

      int numBF = (1 << (stage - 1));
      for (int j = 0; j < numBF; j++) {
        float c = cos_coefficients_table[j << (8 - stage)];
        float s = sin_coefficients_table[j << (8 - stage)];
        int i_lower = j + numBF;
        float temp_R =
            X_R_3[i * 512 + i_lower] * c - X_I_3[i * 512 + i_lower] * s;
        float temp_I =
            X_I_3[i * 512 + i_lower] * c + X_R_3[i * 512 + i_lower] * s;
        X_R_3[i * 512 + i_lower] = X_R_3[i * 512 + j] - temp_R;
        X_I_3[i * 512 + i_lower] = X_I_3[i * 512 + j] - temp_I;
        X_R_3[i * 512 + j] = X_R_3[i * 512 + j] + temp_R;
        X_I_3[i * 512 + j] = X_I_3[i * 512 + j] + temp_I;
      }
    }

loop_4:
  for (int i = 0; i < 2; i++)
    for (int stage = 1; stage <= 8; stage++) {
      int numBF = (1 << (stage - 1));
      for (int j = 0; j < numBF; j++) {
        float c = cos_coefficients_table[j << (8 - stage)];
        float s = sin_coefficients_table[j << (8 - stage)];
        int i_lower = j + numBF;
        float temp_R =
            X_R_4[i * 512 + i_lower] * c - X_I_4[i * 512 + i_lower] * s;
        float temp_I =
            X_I_4[i * 512 + i_lower] * c + X_R_4[i * 512 + i_lower] * s;
        X_R_4[i * 512 + i_lower] = X_R_4[i * 512 + j] - temp_R;
        X_I_4[i * 512 + i_lower] = X_I_4[i * 512 + j] - temp_I;
        X_R_4[i * 512 + j] = X_R_4[i * 512 + j] + temp_R;
        X_I_4[i * 512 + j] = X_I_4[i * 512 + j] + temp_I;
      }
    }

loop_5:
  for (int i = 0; i < 2; i++)
    for (int stage = 1; stage <= 8; stage++) {
      int numBF = (1 << (stage - 1));
      for (int j = 0; j < numBF; j++) {
        float c = cos_coefficients_table[j << (8 - stage)];
        float s = sin_coefficients_table[j << (8 - stage)];
        int i_lower = j + numBF;
        float temp_R =
            X_R_5[i * 512 + i_lower] * c - X_I_5[i * 512 + i_lower] * s;
        float temp_I =
            X_I_5[i * 512 + i_lower] * c + X_R_5[i * 512 + i_lower] * s;
        X_R_5[i * 512 + i_lower] = X_R_5[i * 512 + j] - temp_R;
        X_I_5[i * 512 + i_lower] = X_I_5[i * 512 + j] - temp_I;
        X_R_5[i * 512 + j] = X_R_5[i * 512 + j] + temp_R;
        X_I_5[i * 512 + j] = X_I_5[i * 512 + j] + temp_I;
      }
    }

loop_6:
  for (int i = 0; i < 2; i++)
    for (int stage = 1; stage <= 8; stage++) {
      int numBF = (1 << (stage - 1));
      for (int j = 0; j < numBF; j++) {
        float c = cos_coefficients_table[j << (8 - stage)];
        float s = sin_coefficients_table[j << (8 - stage)];
        int i_lower = j + numBF;
        float temp_R =
            X_R_6[i * 512 + i_lower] * c - X_I_6[i * 512 + i_lower] * s;
        float temp_I =
            X_I_6[i * 512 + i_lower] * c + X_R_6[i * 512 + i_lower] * s;
        X_R_6[i * 512 + i_lower] = X_R_6[i * 512 + j] - temp_R;
        X_I_6[i * 512 + i_lower] = X_I_6[i * 512 + j] - temp_I;
        X_R_6[i * 512 + j] = X_R_6[i * 512 + j] + temp_R;
        X_I_6[i * 512 + j] = X_I_6[i * 512 + j] + temp_I;
      }
    }

loop_7:
  for (int i = 0; i < 2; i++)
    for (int stage = 1; stage <= 8; stage++) {
      int numBF = (1 << (stage - 1));
      for (int j = 0; j < numBF; j++) {
        float c = cos_coefficients_table[j << (8 - stage)];
        float s = sin_coefficients_table[j << (8 - stage)];
        int i_lower = j + numBF;
        float temp_R =
            X_R_7[i * 512 + i_lower] * c - X_I_7[i * 512 + i_lower] * s;
        float temp_I =
            X_I_7[i * 512 + i_lower] * c + X_R_7[i * 512 + i_lower] * s;
        X_R_7[i * 512 + i_lower] = X_R_7[i * 512 + j] - temp_R;
        X_I_7[i * 512 + i_lower] = X_I_7[i * 512 + j] - temp_I;
        X_R_7[i * 512 + j] = X_R_7[i * 512 + j] + temp_R;
        X_I_7[i * 512 + j] = X_I_7[i * 512 + j] + temp_I;
      }
    }
}

int main() {
  float X_R_0[1024], X_R_1[1024], X_R_2[1024], X_R_3[1024], X_R_4[1024],
      X_R_5[1024], X_R_6[1024], X_R_7[1024];
  float X_I_0[1024], X_I_1[1024], X_I_2[1024], X_I_3[1024], X_I_4[1024],
      X_I_5[1024], X_I_6[1024], X_I_7[1024];

  float cos_coefficients_table[512] = {
      1.000000,  0.999981,  0.999925,  0.999831,  0.999699,  0.999529,
      0.999322,  0.999078,  0.998795,  0.998476,  0.998118,  0.997723,
      0.997290,  0.996820,  0.996313,  0.995767,  0.995185,  0.994565,
      0.993907,  0.993212,  0.992480,  0.991710,  0.990903,  0.990058,
      0.989177,  0.988258,  0.987301,  0.986308,  0.985278,  0.984210,
      0.983105,  0.981964,  0.980785,  0.979570,  0.978317,  0.977028,
      0.975702,  0.974339,  0.972940,  0.971504,  0.970031,  0.968522,
      0.966976,  0.965394,  0.963776,  0.962121,  0.960431,  0.958703,
      0.956940,  0.955141,  0.953306,  0.951435,  0.949528,  0.947586,
      0.945607,  0.943593,  0.941544,  0.939459,  0.937339,  0.935184,
      0.932993,  0.930767,  0.928506,  0.926210,  0.923880,  0.921514,
      0.919114,  0.916679,  0.914210,  0.911706,  0.909168,  0.906596,
      0.903989,  0.901349,  0.898674,  0.895966,  0.893224,  0.890449,
      0.887640,  0.884797,  0.881921,  0.879012,  0.876070,  0.873095,
      0.870087,  0.867046,  0.863973,  0.860867,  0.857729,  0.854558,
      0.851355,  0.848120,  0.844854,  0.841555,  0.838225,  0.834863,
      0.831470,  0.828045,  0.824589,  0.821103,  0.817585,  0.814036,
      0.810457,  0.806848,  0.803208,  0.799537,  0.795837,  0.792107,
      0.788346,  0.784557,  0.780737,  0.776888,  0.773010,  0.769103,
      0.765167,  0.761202,  0.757209,  0.753187,  0.749136,  0.745058,
      0.740951,  0.736817,  0.732654,  0.728464,  0.724247,  0.720003,
      0.715731,  0.711432,  0.707107,  0.702755,  0.698376,  0.693971,
      0.689541,  0.685084,  0.680601,  0.676093,  0.671559,  0.667000,
      0.662416,  0.657807,  0.653173,  0.648514,  0.643832,  0.639124,
      0.634393,  0.629638,  0.624859,  0.620057,  0.615232,  0.610383,
      0.605511,  0.600616,  0.595699,  0.590760,  0.585798,  0.580814,
      0.575808,  0.570781,  0.565732,  0.560662,  0.555570,  0.550458,
      0.545325,  0.540171,  0.534998,  0.529804,  0.524590,  0.519356,
      0.514103,  0.508830,  0.503538,  0.498228,  0.492898,  0.487550,
      0.482184,  0.476799,  0.471397,  0.465976,  0.460539,  0.455084,
      0.449611,  0.444122,  0.438616,  0.433094,  0.427555,  0.422000,
      0.416430,  0.410843,  0.405241,  0.399624,  0.393992,  0.388345,
      0.382683,  0.377007,  0.371317,  0.365613,  0.359895,  0.354164,
      0.348419,  0.342661,  0.336890,  0.331106,  0.325310,  0.319502,
      0.313682,  0.307850,  0.302006,  0.296151,  0.290285,  0.284408,
      0.278520,  0.272621,  0.266713,  0.260794,  0.254866,  0.248928,
      0.242980,  0.237024,  0.231058,  0.225084,  0.219101,  0.213110,
      0.207111,  0.201105,  0.195090,  0.189069,  0.183040,  0.177004,
      0.170962,  0.164913,  0.158858,  0.152797,  0.146730,  0.140658,
      0.134581,  0.128498,  0.122411,  0.116319,  0.110222,  0.104122,
      0.098017,  0.091909,  0.085797,  0.079682,  0.073565,  0.067444,
      0.061321,  0.055195,  0.049068,  0.042938,  0.036807,  0.030675,
      0.024541,  0.018407,  0.012272,  0.006136,  0.000000,  -0.006136,
      -0.012272, -0.018407, -0.024541, -0.030675, -0.036807, -0.042938,
      -0.049068, -0.055195, -0.061321, -0.067444, -0.073565, -0.079682,
      -0.085797, -0.091909, -0.098017, -0.104122, -0.110222, -0.116319,
      -0.122411, -0.128498, -0.134581, -0.140658, -0.146730, -0.152797,
      -0.158858, -0.164913, -0.170962, -0.177004, -0.183040, -0.189069,
      -0.195090, -0.201105, -0.207111, -0.213110, -0.219101, -0.225084,
      -0.231058, -0.237024, -0.242980, -0.248928, -0.254866, -0.260794,
      -0.266713, -0.272621, -0.278520, -0.284408, -0.290285, -0.296151,
      -0.302006, -0.307850, -0.313682, -0.319502, -0.325310, -0.331106,
      -0.336890, -0.342661, -0.348419, -0.354164, -0.359895, -0.365613,
      -0.371317, -0.377007, -0.382683, -0.388345, -0.393992, -0.399624,
      -0.405241, -0.410843, -0.416430, -0.422000, -0.427555, -0.433094,
      -0.438616, -0.444122, -0.449611, -0.455084, -0.460539, -0.465976,
      -0.471397, -0.476799, -0.482184, -0.487550, -0.492898, -0.498228,
      -0.503538, -0.508830, -0.514103, -0.519356, -0.524590, -0.529804,
      -0.534998, -0.540171, -0.545325, -0.550458, -0.555570, -0.560662,
      -0.565732, -0.570781, -0.575808, -0.580814, -0.585798, -0.590760,
      -0.595699, -0.600616, -0.605511, -0.610383, -0.615232, -0.620057,
      -0.624859, -0.629638, -0.634393, -0.639124, -0.643832, -0.648514,
      -0.653173, -0.657807, -0.662416, -0.667000, -0.671559, -0.676093,
      -0.680601, -0.685084, -0.689541, -0.693971, -0.698376, -0.702755,
      -0.707107, -0.711432, -0.715731, -0.720003, -0.724247, -0.728464,
      -0.732654, -0.736817, -0.740951, -0.745058, -0.749136, -0.753187,
      -0.757209, -0.761202, -0.765167, -0.769103, -0.773010, -0.776888,
      -0.780737, -0.784557, -0.788346, -0.792107, -0.795837, -0.799537,
      -0.803208, -0.806848, -0.810457, -0.814036, -0.817585, -0.821103,
      -0.824589, -0.828045, -0.831470, -0.834863, -0.838225, -0.841555,
      -0.844854, -0.848120, -0.851355, -0.854558, -0.857729, -0.860867,
      -0.863973, -0.867046, -0.870087, -0.873095, -0.876070, -0.879012,
      -0.881921, -0.884797, -0.887640, -0.890449, -0.893224, -0.895966,
      -0.898674, -0.901349, -0.903989, -0.906596, -0.909168, -0.911706,
      -0.914210, -0.916679, -0.919114, -0.921514, -0.923880, -0.926210,
      -0.928506, -0.930767, -0.932993, -0.935184, -0.937339, -0.939459,
      -0.941544, -0.943593, -0.945607, -0.947586, -0.949528, -0.951435,
      -0.953306, -0.955141, -0.956940, -0.958703, -0.960431, -0.962121,
      -0.963776, -0.965394, -0.966976, -0.968522, -0.970031, -0.971504,
      -0.972940, -0.974339, -0.975702, -0.977028, -0.978317, -0.979570,
      -0.980785, -0.981964, -0.983105, -0.984210, -0.985278, -0.986308,
      -0.987301, -0.988258, -0.989177, -0.990058, -0.990903, -0.991710,
      -0.992480, -0.993212, -0.993907, -0.994565, -0.995185, -0.995767,
      -0.996313, -0.996820, -0.997290, -0.997723, -0.998118, -0.998476,
      -0.998795, -0.999078, -0.999322, -0.999529, -0.999699, -0.999831,
      -0.999925, -0.999981};

  float sin_coefficients_table[512] = {
      0.000000,  -0.006136, -0.012272, -0.018407, -0.024541, -0.030675,
      -0.036807, -0.042938, -0.049068, -0.055195, -0.061321, -0.067444,
      -0.073565, -0.079682, -0.085797, -0.091909, -0.098017, -0.104122,
      -0.110222, -0.116319, -0.122411, -0.128498, -0.134581, -0.140658,
      -0.146730, -0.152797, -0.158858, -0.164913, -0.170962, -0.177004,
      -0.183040, -0.189069, -0.195090, -0.201105, -0.207111, -0.213110,
      -0.219101, -0.225084, -0.231058, -0.237024, -0.242980, -0.248928,
      -0.254866, -0.260794, -0.266713, -0.272621, -0.278520, -0.284408,
      -0.290285, -0.296151, -0.302006, -0.307850, -0.313682, -0.319502,
      -0.325310, -0.331106, -0.336890, -0.342661, -0.348419, -0.354164,
      -0.359895, -0.365613, -0.371317, -0.377007, -0.382683, -0.388345,
      -0.393992, -0.399624, -0.405241, -0.410843, -0.416430, -0.422000,
      -0.427555, -0.433094, -0.438616, -0.444122, -0.449611, -0.455084,
      -0.460539, -0.465976, -0.471397, -0.476799, -0.482184, -0.487550,
      -0.492898, -0.498228, -0.503538, -0.508830, -0.514103, -0.519356,
      -0.524590, -0.529804, -0.534998, -0.540171, -0.545325, -0.550458,
      -0.555570, -0.560662, -0.565732, -0.570781, -0.575808, -0.580814,
      -0.585798, -0.590760, -0.595699, -0.600616, -0.605511, -0.610383,
      -0.615232, -0.620057, -0.624859, -0.629638, -0.634393, -0.639124,
      -0.643832, -0.648514, -0.653173, -0.657807, -0.662416, -0.667000,
      -0.671559, -0.676093, -0.680601, -0.685084, -0.689541, -0.693971,
      -0.698376, -0.702755, -0.707107, -0.711432, -0.715731, -0.720003,
      -0.724247, -0.728464, -0.732654, -0.736817, -0.740951, -0.745058,
      -0.749136, -0.753187, -0.757209, -0.761202, -0.765167, -0.769103,
      -0.773010, -0.776888, -0.780737, -0.784557, -0.788346, -0.792107,
      -0.795837, -0.799537, -0.803208, -0.806848, -0.810457, -0.814036,
      -0.817585, -0.821103, -0.824589, -0.828045, -0.831470, -0.834863,
      -0.838225, -0.841555, -0.844854, -0.848120, -0.851355, -0.854558,
      -0.857729, -0.860867, -0.863973, -0.867046, -0.870087, -0.873095,
      -0.876070, -0.879012, -0.881921, -0.884797, -0.887640, -0.890449,
      -0.893224, -0.895966, -0.898674, -0.901349, -0.903989, -0.906596,
      -0.909168, -0.911706, -0.914210, -0.916679, -0.919114, -0.921514,
      -0.923880, -0.926210, -0.928506, -0.930767, -0.932993, -0.935184,
      -0.937339, -0.939459, -0.941544, -0.943593, -0.945607, -0.947586,
      -0.949528, -0.951435, -0.953306, -0.955141, -0.956940, -0.958703,
      -0.960431, -0.962121, -0.963776, -0.965394, -0.966976, -0.968522,
      -0.970031, -0.971504, -0.972940, -0.974339, -0.975702, -0.977028,
      -0.978317, -0.979570, -0.980785, -0.981964, -0.983105, -0.984210,
      -0.985278, -0.986308, -0.987301, -0.988258, -0.989177, -0.990058,
      -0.990903, -0.991710, -0.992480, -0.993212, -0.993907, -0.994565,
      -0.995185, -0.995767, -0.996313, -0.996820, -0.997290, -0.997723,
      -0.998118, -0.998476, -0.998795, -0.999078, -0.999322, -0.999529,
      -0.999699, -0.999831, -0.999925, -0.999981, -1.000000, -0.999981,
      -0.999925, -0.999831, -0.999699, -0.999529, -0.999322, -0.999078,
      -0.998795, -0.998476, -0.998118, -0.997723, -0.997290, -0.996820,
      -0.996313, -0.995767, -0.995185, -0.994565, -0.993907, -0.993212,
      -0.992480, -0.991710, -0.990903, -0.990058, -0.989177, -0.988258,
      -0.987301, -0.986308, -0.985278, -0.984210, -0.983105, -0.981964,
      -0.980785, -0.979570, -0.978317, -0.977028, -0.975702, -0.974339,
      -0.972940, -0.971504, -0.970031, -0.968522, -0.966976, -0.965394,
      -0.963776, -0.962121, -0.960431, -0.958703, -0.956940, -0.955141,
      -0.953306, -0.951435, -0.949528, -0.947586, -0.945607, -0.943593,
      -0.941544, -0.939459, -0.937339, -0.935184, -0.932993, -0.930767,
      -0.928506, -0.926210, -0.923880, -0.921514, -0.919114, -0.916679,
      -0.914210, -0.911706, -0.909168, -0.906596, -0.903989, -0.901349,
      -0.898674, -0.895966, -0.893224, -0.890449, -0.887640, -0.884797,
      -0.881921, -0.879012, -0.876070, -0.873095, -0.870087, -0.867046,
      -0.863973, -0.860867, -0.857729, -0.854558, -0.851355, -0.848120,
      -0.844854, -0.841555, -0.838225, -0.834863, -0.831470, -0.828045,
      -0.824589, -0.821103, -0.817585, -0.814036, -0.810457, -0.806848,
      -0.803208, -0.799537, -0.795837, -0.792107, -0.788346, -0.784557,
      -0.780737, -0.776888, -0.773010, -0.769103, -0.765167, -0.761202,
      -0.757209, -0.753187, -0.749136, -0.745058, -0.740951, -0.736817,
      -0.732654, -0.728464, -0.724247, -0.720003, -0.715731, -0.711432,
      -0.707107, -0.702755, -0.698376, -0.693971, -0.689541, -0.685084,
      -0.680601, -0.676093, -0.671559, -0.667000, -0.662416, -0.657807,
      -0.653173, -0.648514, -0.643832, -0.639124, -0.634393, -0.629638,
      -0.624859, -0.620057, -0.615232, -0.610383, -0.605511, -0.600616,
      -0.595699, -0.590760, -0.585798, -0.580814, -0.575808, -0.570781,
      -0.565732, -0.560662, -0.555570, -0.550458, -0.545325, -0.540171,
      -0.534998, -0.529804, -0.524590, -0.519356, -0.514103, -0.508830,
      -0.503538, -0.498228, -0.492898, -0.487550, -0.482184, -0.476799,
      -0.471397, -0.465976, -0.460539, -0.455084, -0.449611, -0.444122,
      -0.438616, -0.433094, -0.427555, -0.422000, -0.416430, -0.410843,
      -0.405241, -0.399624, -0.393992, -0.388345, -0.382683, -0.377007,
      -0.371317, -0.365613, -0.359895, -0.354164, -0.348419, -0.342661,
      -0.336890, -0.331106, -0.325310, -0.319502, -0.313682, -0.307850,
      -0.302006, -0.296151, -0.290285, -0.284408, -0.278520, -0.272621,
      -0.266713, -0.260794, -0.254866, -0.248928, -0.242980, -0.237024,
      -0.231058, -0.225084, -0.219101, -0.213110, -0.207111, -0.201105,
      -0.195090, -0.189069, -0.183040, -0.177004, -0.170962, -0.164913,
      -0.158858, -0.152797, -0.146730, -0.140658, -0.134581, -0.128498,
      -0.122411, -0.116319, -0.110222, -0.104122, -0.098017, -0.091909,
      -0.085797, -0.079682, -0.073565, -0.067444, -0.061321, -0.055195,
      -0.049068, -0.042938, -0.036807, -0.030675, -0.024541, -0.018407,
      -0.012272, -0.006136};

  srand(9);
  for (int i = 0; i < 1024; i++) {
    X_R_0[i] = rand();
    X_R_1[i] = rand();
    X_R_2[i] = rand();
    X_R_3[i] = rand();
    X_R_4[i] = rand();
    X_R_5[i] = rand();
    X_R_6[i] = rand();
    X_R_7[i] = rand();
    X_I_0[i] = rand();
    X_I_1[i] = rand();
    X_I_2[i] = rand();
    X_I_3[i] = rand();
    X_I_4[i] = rand();
    X_I_5[i] = rand();
    X_I_6[i] = rand();
    X_I_7[i] = rand();
  }

  fft(X_R_0, X_R_1, X_R_2, X_R_3, X_R_4, X_R_5, X_R_6, X_R_7, X_I_0, X_I_1,
      X_I_2, X_I_3, X_I_4, X_I_5, X_I_6, X_I_7, cos_coefficients_table,
      sin_coefficients_table);

  return 0;
}


#include "levmarq.h"

float g2(float y, float x, float g, float weight){
#pragma SS II=2
	float d, dout;


#include "vecTrans3.h"

int main(){

  float A[2000];
  int in[1000], out[1000];

  for (int i = 0; i < 1000; i++){
    in[i] = i;
    out[i] = i;
  }

    A[i] = 0.6f;
  }

  vecTrans3(A, in, out);

  return 0;
}


// Data set size
#define N 100

#define STEP 1000

#include <stdio.h>

int main() {

  // input initialization
  int i,j,k,t;
  int check;

  int n = 0;

  int m;
  int m_list[STEP] = {1,50} ;

  int ub;

  float x[N];
  float x_ref[N];

  float L[N][N];

  srand(1);

  FILE *f = fopen("iter.dat", "w");
  if (!f)
  {
      printf("Error opening file!\n");
      exit(1);
  }

  for(t=0; t<STEP; t++){

	check = 0;

    //m = m_list[t];
	ub = rand()%(N-1) +1;
	lb = rand()%ub;

	// for full region
    //m = rand()%N;

    // for conflict region
    m = rand()%(ub-lb) + lb;

    printf("\n===== lb: %d ", lb);
    printf("\n===== ub: %d ", ub);
    printf("\n===== m: %d \n", m);

    // reference init
    for (i=0; i<N; i++){
      x[i] = rand()%N;
      x_ref[i] = x[i];
    }

    for (j=0; j<N; j++){
      for (i=0; i<N; i++){
	L[j][i] = rand()%N;
      }
    }

    // run reference kernel
    for(i = lb; i<=ub ; i++){
      x_ref[i] = x_ref[i] - L[i][m]*x_ref[m];
    }

    // run kernel
    kernel_Tri_Sp_Slv(m, lb, ub, x, L);

    // compare
    for (i=0; i<N; i++){
      if (x[i] != x_ref[i]) check = check + 1;
    }

    fprintf(f, "%d\n", ub-lb+1);

    if(check!=0){
    	fclose(f);
    	return 1;
    }

    }

  fclose(f);
  return 0;

  }


// Data set size
#define N 300 // 32, 500, 1000, 2000, 4000

#define _PB_N 200

void kernel_jacobi_2d_imper(int n,
			    int m,
			    float A[N][N])
{
  int i, j;

#pragma HLS ALLOCATION instances=mul limit=3 operation

#pragma scop


// Data set size
#define N 100 //

void kernel_Tri_Sp_Slv(int m,
		       int lb,
		       int ub,
		       float x[N],
		       float L[N][N])
{
  int i;

#pragma HLS ALLOCATION instances=mul limit=1 operation

  // x[i] = x[i] - L[i][j] * x[j], i>j
/* Begin Accelerated Scop */
float* L_flt = L;
float* x_flt = x;
{
  if (m >= lb && ub >= m + 1) {
    for (int c1 = lb; c1 <= ub; c1 += 1)
      #pragma HLS PIPELINE
      x_flt[c1] = x_flt[c1] - L_flt[m + 100 * c1] * x_flt[m];
  } else
    for (int c1 = lb; c1 <= ub; c1 += 1)
      #pragma HLS PIPELINE
      #pragma HLS DEPENDENCE variable=L_flt array inter false
      #pragma HLS DEPENDENCE variable=x_flt array inter false
      x_flt[c1] = x_flt[c1] - L_flt[m + 100 * c1] * x_flt[m];
}

/* End Accelerated Scop */

}


// Data set size
#define N 100
#define NL 3

#define STEP 100

#include <stdio.h>

int main() {

  // input initialization
  int i,kx,ky,t;
  int check = 0;

  int n;
  int n_list[STEP] = {30,30,10} ;

  int nl1;
  int nl1_list[STEP] = {1,1,2} ;

  int nl2;
  int nl2_list[STEP] = {1,2,1} ;

  float sig = 1.0f;
  float a11 = 1.0f; float a12 = 1.0f; float a13 = 1.0f;
  float a21 = 1.0f; float a22 = 1.0f; float a23 = 1.0f;
  float a31 = 1.0f; float a32 = 1.0f; float a33 = 1.0f;

  float du1[N];
  float du2[N];
  float du3[N];
  float u1[NL][N][N];
  float u2[NL][N][N];
  float u3[NL][N][N];

  float du1_ref[N];
  float du2_ref[N];
  float du3_ref[N];
  float u1_ref[NL][N][N];
  float u2_ref[NL][N][N];
  float u3_ref[NL][N][N];

  // test loop
  for(t=0; t<STEP; t++){

	// specific test
//    n = n_list[t];
//    nl1 = nl1_list[t];
//    nl2 = nl2_list[t];

    // random test
    n = rand()%(30) +2;
    nl1 = rand()%NL;
    nl2 = rand()%NL;

    // reference init
    for (ky=0; ky<N; ky++){
      du1[ky] = rand()%N;
      du1_ref[ky] = du1[ky];

      du2[ky] = rand()%N;
      du2_ref[ky] = du2[ky];

      du3[ky] = rand()%N;
      du3_ref[ky] = du3[ky];
    }

    for (i=0; i<NL; i++){
      for (kx=0; kx<N; kx++){
	for (ky=0; ky<N; ky++){
	  u1[i][ky][kx] = rand()%N;
	  u1_ref[i][ky][kx] = u1[i][ky][kx];

	  u2[i][ky][kx] = rand()%N;
	  u2_ref[i][ky][kx] = u2[i][ky][kx];

	  u3[i][ky][kx] = rand()%N;
	  u3_ref[i][ky][kx] = u3[i][ky][kx];
	}
      }
    }

    // run reference kernel
    for ( kx=1 ; kx<4 ; kx++ ){
      for ( ky=1 ; ky<n ; ky++ ) {
	du1_ref[ky] = u1_ref[nl1][ky+1][kx] - u1_ref[nl1][ky-1][kx];
	du2_ref[ky] = u2_ref[nl1][ky+1][kx] - u2_ref[nl1][ky-1][kx];
	du3_ref[ky] = u3_ref[nl1][ky+1][kx] - u3_ref[nl1][ky-1][kx];
	u1_ref[nl2][ky][kx]=
	  u1_ref[nl1][ky][kx]+a11*du1_ref[ky]+a12*du2_ref[ky]+a13*du3_ref[ky] + sig*
	  (u1_ref[nl1][ky][kx+1]-2.0f*u1_ref[nl1][ky][kx]+u1_ref[nl1][ky][kx-1]);
	u2_ref[nl2][ky][kx]=
	  u2_ref[nl1][ky][kx]+a21*du1_ref[ky]+a22*du2_ref[ky]+a23*du3_ref[ky] + sig*
	  (u2_ref[nl1][ky][kx+1]-2.0f*u2_ref[nl1][ky][kx]+u2_ref[nl1][ky][kx-1]);
	u3_ref[nl2][ky][kx]=
	  u3_ref[nl1][ky][kx]+a31*du1_ref[ky]+a32*du2_ref[ky]+a33*du3_ref[ky] + sig*
	  (u3_ref[nl1][ky][kx+1]-2.0f*u3_ref[nl1][ky][kx]+u3_ref[nl1][ky][kx-1]);
      }
    }

    // run kernel
    kernel_adi_int(n, nl1, nl2, du1, du2, du3, u1, u2, u3);

    // compare
    for (ky=0; ky<N; ky++){
      if (du1[ky] != du1_ref[ky]) {
	check = check + 1;
	printf("du1[%d]: %e \n", ky,du1[ky]);
	printf("du1_ref[%d]: %e \n", ky,du1_ref[ky]);
      }
      if (du2[ky] != du2_ref[ky]) {
	check = check + 1;
	printf("du2[%d]: %e \n", ky,du2[ky]);
	printf("du2_ref[%d]: %e \n", ky,du2_ref[ky]);
      }
      if (du3[ky] != du3_ref[ky]) {
	check = check + 1;
	printf("du3[%d]: %e \n", ky,du3[ky]);
	printf("du3_ref[%d]: %e \n", ky,du3_ref[ky]);
      }
    }

    for (i=0; i<NL; i++){
      for (kx=0; kx<N; kx++){
	for (ky=0; ky<N; ky++){


// Data set size
#define N 100 // 32, 500, 1000, 2000, 4000

//kernal from MIT Gauss Pivot: forward reduction part
void kernel_pivot(int k,
		  int n,
		  float A[2*N][2*N])
{
  int i,j;
  //int tmp;

//#pragma HLS ALLOCATION instances=fdiv limit=1 operation
//#pragma HLS ALLOCATION instances=fmul limit=1 operation
//#pragma HLS ALLOCATION instances=fsub limit=1 operation
//#pragma HLS ALLOCATION instances=mul limit=2 operation

/* #pragma scop */
/*   for (i = 0; i < N; i++){ */
/*     #pragma HLS PIPELINE */
/*     tmp = A[k][i]; */
/*     A[k][i] = A[p][i]; */
/*     A[p][i] = tmp;  */
/*   }  */
/* #pragma endscop */

/* Begin Accelerated Scop */

{
  for (int c1 = k + 1; c1 <= n; c1 += 1)
    for (int c3 = k + 1; c3 <= n; c3 += 1)
      #pragma HLS PIPELINE
      #pragma HLS DEPENDENCE variable=A_flt array inter false
      A_flt[200 * c1 + c3] = A_flt[200 * c1 + c3] - (A_flt[200 * k + c3] * A_flt[k + 200 * c1] / A_flt[201 * k]);
}

/* End Accelerated Scop */

}


#define N 128

void kernel_floyd_warshall(int n,
			   float path[N][N])
{
  int i, j, k;

#pragma scop
  for(k = 0; k < N; k++){

    for(i = 0; i < N; i++)
      for(j = 0; j < N; j++)
#pragma HLS PIPELINE
	path[i][j] = path[i][j] < path[i][k] + path[k][j] ? path[i][j] : path[i][k] + path[k][j];


/* Begin Extra Functions Definition */
int min(int a, int b) { return (a<b) ? a : b;}
int max(int a, int b) { return (a>b) ? a : b;}
/* End Extra Functions Definition */

// Data set size
#define N 100 //

void kernel_Tri_Sp_Slv(int m,
		       int lb,
		       int ub,
		       float x[N],
		       float L[N][N])
{
  int i;
  float t;

#pragma HLS ALLOCATION instances=mul limit=1 operation

  // x[i] = x[i] - L[i][j] * x[j], i>j
/* Begin Accelerated Scop */
float* L_flt = L;
float* x_flt = x;
{
  if (m >= lb && ub >= m + 1) {
    if (ub >= m + 1)
      for (int c1 = lb; c1 <= m; c1 += 1)
        #pragma HLS PIPELINE
        #pragma HLS DEPENDENCE variable=L_flt array inter false
        #pragma HLS DEPENDENCE variable=x_flt array inter false
        x_flt[c1] = x_flt[c1] - L_flt[m + 100 * c1] * x_flt[m];
    if (m >= lb)

        #pragma HLS PIPELINE
        #pragma HLS DEPENDENCE variable=L_flt array inter false
        #pragma HLS DEPENDENCE variable=x_flt array inter false
        x_flt[c1] = x_flt[c1] - L_flt[m + 100 * c1] * x_flt[m];
  } else
    for (int c1 = lb; c1 <= ub; c1 += 1)
      #pragma HLS PIPELINE
      #pragma HLS DEPENDENCE variable=L_flt array inter false
      #pragma HLS DEPENDENCE variable=x_flt array inter false
      x_flt[c1] = x_flt[c1] - L_flt[m + 100 * c1] * x_flt[m];
}

/* End Accelerated Scop */

}


// Data set size
#define N 100
#define NL 3

void kernel_adi_int(int n,
			int nl1,
			int nl2,
			float du1[N],
			float du2[N],
			float du3[N],
			float u1[NL][N][N],
			float u2[NL][N][N],
			float u3[NL][N][N])
{
  int kx;
  int ky;

  float sig = 1.0f;
  float a11 = 1.0f; float a12 = 1.0f; float a13 = 1.0f;
  float a21 = 1.0f; float a22 = 1.0f; float a23 = 1.0f;
  float a31 = 1.0f; float a32 = 1.0f; float a33 = 1.0f;

//#pragma HLS ALLOCATION instances=mul limit=2 operation

  // ADI integration
  // Kernal 8 in livermorec
  #pragma scop
  for ( kx=1 ; kx<4 ; kx++ ){

    for ( ky=1 ; ky<n ; ky++ ) {
      #pragma HLS PIPELINE
      du1[ky] = u1[nl1][ky+1][kx] - u1[nl1][ky-1][kx];


// Data set size
#define N 100 // 32, 500, 1000, 2000, 4000

//kernal from MIT Gauss Pivot: forward reduction part

  #pragma scop
  for (i=k+1; i<=n; i++){
    for (j=k+1; j<=n; j++){
      #pragma HLS PIPELINE
      A[i][j] = A[i][j] - A[k][j] * A[i][k] / A[k][k];
    }
  }
  #pragma endscop

}

void kernel_pivot(int k,
		  int n,
		  float A[2*N][2*N])


// Data set size
#define N 100

#define STEP 100

#include <stdio.h>

int main() {

  // input initialization
  int i,j,k,t;
  int check;

  int n = 0;

  int m;
  int m_list[STEP] = {1,50} ;

  int lb;
  int ub;

  float x_ref[N];

  float L[N][N];

  srand(1);

  FILE *f = fopen("iter.dat", "w");
  if (!f)
  {
      printf("Error opening file!\n");
      exit(1);
  }

  for(t=0; t<STEP; t++){

	check = 0;

    //m = m_list[t];
	ub = rand()%(N-1) +1;
	lb = rand()%ub;

	// for full region
    m = rand()%N;

    // for conflict region
    //m = rand()%(ub-lb) + lb;

    printf("\n===== lb: %d ", lb);
    printf("\n===== ub: %d ", ub);
    printf("\n===== m: %d \n", m);

    // reference init
    for (i=0; i<N; i++){
      x[i] = rand()%N;
      x_ref[i] = x[i];
    }

    for (j=0; j<N; j++){
      for (i=0; i<N; i++){
	L[j][i] = rand()%N;
      }
    }

    // run reference kernel
    for(i = lb; i<=ub ; i++){
      x_ref[i] = x_ref[i] - L[i][m]*x_ref[m];
    }

    // run kernel
    kernel_Tri_Sp_Slv(m, lb, ub, x, L);

    // compare
    for (i=0; i<N; i++){
      if (x[i] != x_ref[i]) check = check + 1;
    }

    fprintf(f, "%d\n", ub-lb+1);

    if(check!=0){
    	fclose(f);
    	return 1;
    }

    }

  fclose(f);
  return 0;

  }


// Data set size
#define N 100

#define STEP 100

#include <stdio.h>

int main() {

  // input initialization
  int i,j,k,t;
  int check;

  int m;

  float A[2*N];
  float A_ref[2*N];

  srand(1);

  FILE *f = fopen("iter.dat", "w");
  if (!f)

    check = 0;

    // conflict region random test
    m = rand()%(13) + 1;

    // conlfict region seperate test
    //m = t;

    //m=12;

    printf("\n===== m: %d \n", m);

    // reference init
    for (i=0; i<2*N; i++){
      A[i] = rand()%N;
      A_ref[i] = A[i];
    }

    // run reference kernel
    for (i=0; i<N; i++){
      A_ref[i+m] = A_ref[i] + 0.5f;
    }

    // run kernel
    kernel_dist_param(m, A);

    // compare
    for (i=0; i<2*N; i++){
      if (A[i] != A_ref[i]){
    	  check = check + 1;
    	  printf("*** A[%d] \n", i);
      }
    }

    fprintf(f, "%d\n", N);

    if(check!=0){
      fclose(f);
      return 1;
    }

  }

  fclose(f);
  return 0;

}

    {
      printf("Error opening file!\n");
      exit(1);
    }


// Data set size
#define N 100

#define LB 20

#define STEP 1000

#include <stdio.h>

int main() {

  // input initialization

  int check;

  int n;
  int n_list[STEP] = {LB+20, LB+10, N, LB+1};//{LB+20, LB+10, N, LB+1} ;

  int m;
  int m_list[STEP] = {10, 0, -1, -15}; //{10, 0, -1, -15} ;

  float A[2*N][2*N];
  float A_ref[2*N][2*N];

  srand(1);

  FILE *f = fopen("iter.dat", "w");
  if (!f)
  {
      printf("Error opening file!\n");
      exit(1);
  }

  for(t=0; t<STEP; t++){

	check = 0;

    //n = n_list[t];
    //m = m_list[t];

	// full test
	n = rand()%(2*N-LB) + LB +1;
	m = rand()%(2*N-n+LB +1) - LB;

	// conflict region test
//	do{
//		n = rand()%(2*N-LB) + LB +1;
//		m = rand()%(2*N-n+LB +1) - LB;
//	}
//	while(!(m + 40 >= n && n >= m + 21 && n + m >= 21));

    printf("\n===== n: %d \t| m: %d \n", n, m);

    // reference init
    for (j=0; j<2*N; j++){
      for (i=0; i<2*N; i++){
	A[j][i] = rand()%N;
	A_ref[j][i] = A[j][i];
      }
    }

    // run reference kernel
    for (j=N; j<2*N; j++){
      for (i=LB; i<n; i++){
	A_ref[j][i] = A_ref[j-1][i+m] + 0.5f;
      }
    }

    // run kernel
    kernel_typ_loop(m, n, A);

    // compare
    for (j=0; j<2*N; j++){
      for (i=0; i<2*N; i++){
	if (A[j][i] != A_ref[j][i]) check = check + 1;
      }
    }

    fprintf(f, "%d\n", N*(n-LB));

    if(check!=0){
    	fclose(f);
    	return 1;
    }

  }

  fclose(f);
  return 0;

}


/*
 * options.h - Defines possible command line options
 *
 * Copyright (C) 2003 Brailcom, o.p.s.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * $Id: options.h,v 1.10 2006-07-11 16:12:27 hanke Exp $
 */

#include <getopt.h>
#include "speechd_types.h"

extern signed int rate;
extern signed int pitch;
extern signed int pitch_range;
extern signed int volume;

extern int list_output_modules;
extern char *output_module;
extern char *sound_icon;
extern char *language;
extern char *voice_type;
extern char *punctuation_mode;

extern int pipe_mode;
extern int character;
extern int key;
extern SPDDataMode ssml_mode;
extern int spelling;
extern int wait_till_end;
extern int stop_previous;
extern int cancel_previous;
extern int list_synthesis_voices;
extern char *synthesis_voice;

extern char *application_name;
extern char *connection_name;

static struct option long_options[] = {
	{"rate", 1, 0, 'r'},
	{"pitch", 1, 0, 'p'},
	{"pitch-range", 1, 0, 'R'},
	{"volume", 1, 0, 'i'},
	{"output-module", 1, 0, 'o'},
	{"list-output-modules", no_argument, 0, 'O'},
	{"sound-icon", required_argument, 0, 'I'},
	{"language", 1, 0, 'l'},
	{"voice-type", 1, 0, 't'},
	{"list-synthesis-voices", no_argument, 0, 'L'},
	{"synthesis-voice", required_argument, 0, 'y'},
	{"character", 0, 0, 'c'},
	{"key", 0, 0, 'k'},
	{"punctuation-mode", 1, 0, 'm'},
	{"spelling", 0, 0, 's'},
	{"ssml", 0, 0, 'x'},
	{"pipe-mode", 0, 0, 'e'},
	{"priority", 1, 0, 'P'},
	{"application-name", 1, 0, 'N'},
	{"connection-name", 1, 0, 'n'},
	{"wait", 0, 0, 'w'},
	{"stop", 1, 0, 'S'},
	{"cancel", no_argument, 0, 'C'},
	{"version", 0, 0, 'v'},
	{"help", 0, 0, 'h'},
	{0, 0, 0, 0}
};

static char *short_options = "r:p:R:i:l:o:OI:t:Ly:ckm:sxeP:N:n:wSCvh";

int options_parse(int argc, char *argv[]);
void options_print_version(void);
void options_print_help(char *argv[]);


/* server.c -- Server part of spdsend
   Author: Milan Zamazal <pdm@brailcom.org>
*/

/* Copyright (C) 2004 Brailcom, o.p.s.

   COPYRIGHT NOTICE

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 2, or (at your option) any later
   version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "spdsend.h"
#include "../../common/common.h"

#ifndef USE_THREADS
#define USE_THREADS 1
#endif

#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#if USE_THREADS
#include <pthread.h>
#endif
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>

#ifndef HAVE_GETLINE
/*
 * Added by Willie Walker - getline was a GNU libc extension, later adopted
 * in the POSIX.1-2008 standard, but not yet found on all systems.
 */
ssize_t getline(char **lineptr, size_t * n, FILE * f);
#endif

/* Utilities */

static void system_error(const char *message)
{
	perror(message);
	exit(1);
}

/* Connection management */

Stream *connections;
#if USE_THREADS
pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif

static Stream get_connection(Connection_Id id)
{
	if (id < CONNECTION_ID_MIN || id >= CONNECTION_ID_MAX)
		return NONE;
	return connections[id];
}

static void set_connection(Connection_Id id, Stream s)
{
#if USE_THREADS
	pthread_mutex_lock(&connections_mutex);
#endif
	connections[id] = s;
#if USE_THREADS
	pthread_mutex_unlock(&connections_mutex);
#endif
}

static Connection_Id new_connection(Stream s)
{
#if USE_THREADS
	pthread_mutex_lock(&connections_mutex);
#endif
	int id;
	for (id = CONNECTION_ID_MIN;
	     id < CONNECTION_ID_MAX && connections[id] != NONE; id++) ;
	if (id >= CONNECTION_ID_MAX)
	{
#if USE_THREADS
		pthread_mutex_unlock(&connections_mutex);
#endif
		return NONE;
	}
	connections[id] = s;
#if USE_THREADS
	pthread_mutex_unlock(&connections_mutex);
#endif
	return id;
}

static Connection_Id do_open_connection(const char *host, int port)
{
	int sock = socket(AF_INET, SOCK_STREAM, 0);

	if (sock < 0)
		return NONE;

	{
		struct sockaddr_in name;
		name.sin_family = AF_INET;
		name.sin_port = htons(port);
		{
			struct hostent *hostinfo;
			hostinfo = gethostbyname(host);
			if (hostinfo == NULL) {
				close(sock);
				return NONE;
			}
			name.sin_addr = *(struct in_addr *)hostinfo->h_addr;
		}
		if (connect(sock, (struct sockaddr *)&name, sizeof(name)) < 0) {
			close(sock);
			return NONE;
		}
		{
			int arg = 1;
			setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &arg,
				   sizeof(int));
		}
	}

	{

		if (id == NONE)
			close(sock);
		return id;
	}
}

static Success do_close_connection(Connection_Id id)
{
	Stream c = get_connection(id);
	if (c == NONE)
		return ERROR;
	close(c);
	set_connection(id, NONE);
	return OK;
}

static Success do_send_data(Connection_Id id, Stream from, Stream to,
			    Success(*forwarder) (Stream, Stream, bool))
{
	int sock = get_connection(id);
	if (sock == NONE)
		return ERROR;
	if (from == NONE)
		from = sock;
	else if (to == NONE)
		to = sock;
	{
		Success result = ((*forwarder) (from, to, false));
		if (result != OK)
			do_close_connection(id);
		return result;
	}
}

/* Processing requests */

/* Protocol:

   Client request:
     First comes the action code, of the type Action.
     If Action is A_OPEN, the following data follows:
       int port, int strlen(hostname), hostname
     Else:
       Connection_Id
     Then, if Action is A_DATA, the SSIP lines follow.

   Server answer:
     The result code, of the type Result.
     If Result is OK, Connection_Id follows.
     Additionally, if Action is A_DATA, SSIP reply follows.
*/

static Success report(Stream s, Result code)
{
	return write_data(s, &code, sizeof(Result));
}

static Success report_ok(Stream s, Connection_Id id)
{
	if (report(s, OK_CODE) == OK &&
	    write_data(s, &id, sizeof(Connection_Id)) == OK)
		return OK;
	else
		return ERROR;
}

static Success report_error(Stream s)
{
	return report(s, ER_CODE);
}

static Connection_Id read_id(Stream s)
{
	Connection_Id id;
	if (read_data(s, &id, sizeof(Connection_Id)) == ERROR)
		return NONE;
	return id;
}

static Success forward_ssip_answer(Stream from, Stream to, bool _closep)
{
	int result = OK;
	FILE *f = fdopen(from, "r");
	size_t line_size = 256;
	char *line = malloc(line_size);
	if (line == NULL)
		system_error("memory allocation");

	while (1) {
		int n = getline(&line, &line_size, f);
		if (n < 0 || write_data(to, line, n) == ERROR) {
			result = ERROR;
			break;
		}
		if (n > 3 && line[3] == ' ')
			break;
	}

	free(line);
	return result;
}

static void process_open(Stream s)
{
	Connection_Id id;
	int port;
	int hostlen;

	if (read_data(s, &port, sizeof(int)) != sizeof(int)) {
		report_error(s);
		return;
	}
	if (read_data(s, &hostlen, sizeof(int)) != sizeof(int)) {
		report_error(s);
		return;
	}
	{
		char *host = malloc(hostlen + 1);
		if (host == NULL)
			system_error("memory allocation");
		if (read_data(s, host, hostlen) != hostlen) {
			free(host);
			report_error(s);
			return;
		}
		host[hostlen] = '\0';
		id = do_open_connection(host, port);
		free(host);
	}

	if (id == NONE)
		report_error(s);
	else
		report_ok(s, id);
}

static void process_close(Stream s)
{
	Connection_Id id = read_id(s);
	if (id != NONE && do_close_connection(id) == OK)
		report_ok(s, id);
	else
		report_error(s);
}

static void process_data(Stream s)
{
	Connection_Id id = read_id(s);
	if (id != NONE)
		report_ok(s, id);
	else
		report_error(s);

	if (do_send_data(id, s, NONE, forward_data) == OK)
		do_send_data(id, NONE, s, forward_ssip_answer);
}

static void process_request(Stream s)
{
	Action action;

	if (read_data(s, &action, sizeof(Action)) == NONE)
		return;

	if (action == A_OPEN)
		process_open(s);
	else if (action == A_CLOSE)
		process_close(s);
	else if (action == A_DATA)
		process_data(s);
	else
		report_error(s);

	close(s);
}

#if USE_THREADS
static void *process_request_thread(void *s)
{
	Stream s_deref = *((Stream *) s);
	spd_pthread_setname("process_request_thread");
	free(s);
	pthread_detach(pthread_self());
	process_request(s_deref);
	return NULL;
}
#endif

/* Starting the server */

static const char *login_name()
{
	return getpwuid(getuid())->pw_name;
}

static char *server_socket_name()
{
	char *name;
	if (asprintf(&name, "/tmp/spdsend-server.%s", login_name()) < 0)
		system_error("memory allocation");
	return name;
}

static void serve()
{
	struct sockaddr_un name;
	int sock;
	size_t size;
	char *filename = server_socket_name();

	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
	if (sock < 0)
		system_error("socket creation");

	name.sun_family = AF_LOCAL;
	strncpy(name.sun_path, filename, sizeof(name.sun_path));
	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
	size = (offsetof(struct sockaddr_un, sun_path)
		+ strlen(name.sun_path) + 1);
	if (bind(sock, (struct sockaddr *)&name, size) < 0)
		system_error("bind");
	if (listen(sock, LISTEN_QUEUE_LENGTH) < 0)
		system_error("listen");
	free(filename);

	while (1) {
		struct sockaddr_un client_address;
		socklen_t client_address_len = sizeof(client_address);
		Stream *s = malloc(sizeof(Stream));
		if (s == NULL)
			system_error("memory allocation");
		*s = accept(sock, (struct sockaddr *)&client_address,
			    &client_address_len);
		if (*s < 0) {
			free(s);
			break;
		}
		{
#if USE_THREADS
			pthread_t tid;
			if (pthread_create(&tid, NULL, &process_request_thread, s))
#endif
			{
				process_request(*s);
				free(s);
			}
		}
	}
	close(sock);
}

static void daemonize()
{
	int ret = 0;
	if (fork() != 0)
		exit(0);
	setsid();
	signal(SIGHUP, SIG_IGN);
	if (fork() != 0)
		exit(0);
	if ((ret = chdir("/")) != 0)
		fputs("server.c:daemonize: could not chdir", stderr);
	exit(1);
	umask(0);
	{
		int i;
		for (i = 0; i < 4; i++)
			close(i);
	}
}

static void init_connections()
{
	connections = malloc(CONNECTION_ID_MAX * sizeof(Connection_Id));
	if (connections == NULL)
		system_error("memory allocation");
	{
		int i;
		for (i = CONNECTION_ID_MIN; i < CONNECTION_ID_MAX; i++)
			connections[i] = NONE;
	}
}

static void start_server()
{
	const char *socket_name = server_socket_name();
	unlink(socket_name);

	{
		int pid = fork();
		if (pid == -1)
			system_error("fork");

		if (pid == 0) {
			daemonize();
			init_connections();
			serve();
			unlink(socket_name);
			exit(0);
		} else
			sleep(1);
	}
}

static int connect_server()
{
	struct sockaddr_un name;
	int sock = socket(AF_LOCAL, SOCK_STREAM, 0);
	int name_size;
	if (sock < 0)
		return NONE;
	name.sun_family = AF_LOCAL;
	strncpy(name.sun_path, server_socket_name(), sizeof(name.sun_path));
	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
	name_size = (offsetof(struct sockaddr_un, sun_path)
		     + strlen(name.sun_path) + 1);

	if (connect(sock, (struct sockaddr *)&name, name_size) < 0) {
		close(sock);
		return NONE;
	} else
		return sock;
}

/* External functions */

Stream open_server()
{
	Stream s;

	s = connect_server();
	if (s == NONE) {
		start_server();
		s = connect_server();
	}
	if (s == NONE)
		return NONE;

	return s;
}

Connection_Id id = new_connection(sock);


/* spdsend.c -- Send SSIP commands to Speech Dispatcher
   Author: Milan Zamazal <pdm@brailcom.org>
*/

/* Copyright (C) 2004 Brailcom, o.p.s.

   COPYRIGHT NOTICE

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 2, or (at your option) any later
   version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "spdsend.h"

const char *const SPDSEND_VERSION = "0.0.0";

#ifndef HAVE_GETLINE
/*
 * Added by Willie Walker - getline was a GNU libc extension, later adopted
 * in the POSIX.1-2008 standard, but not yet found on all systems.
 */
#define BUFFER_LEN 256
ssize_t getline(char **lineptr, size_t * n, FILE * f)
{
	int ch;
	size_t m = 0;
	ssize_t buf_len = 0;
	char *buf = NULL;
	char *p = NULL;

	if (errno != 0) {
		errno = 0;
	}
	while ((ch = getc(f)) != EOF) {
		if (errno != 0)
			return -1;
		if (m++ >= buf_len) {
			buf_len += BUFFER_LEN;
			buf = (char *)realloc(buf, buf_len + 1);
			if (buf == NULL) {
				return -1;
			}
			p = buf + buf_len - BUFFER_LEN;
		}
		*p = ch;
		p++;
		if (ch == '\n')
			break;
	}
	if (m == 0) {
		return -1;
	} else {
		*p = '\0';
		*lineptr = buf;
		*n = m;
		return m;
	}
}
#endif /* HAVE_GETLINE */

static void usage(const char *const message)
{
	if (message != NULL)
		fprintf(stderr, "spdsend: %s\n", message);
	fprintf(stderr,
		"usage: spdsend { --open SERVER PORT | --close ID | --send ID }\n");
	exit(EXIT_ERROR);
}

static long string_to_number(const char *string,
			     long low_limit, long high_limit)
{
	char *tailptr;
	errno = 0;
	long int number = strtol(string, &tailptr, 0);
	if (errno || *tailptr || number < low_limit || number > high_limit)
		usage("Invalid parameter");
	return number;
}

int main(int argc, char **argv)
{
	if (argc < 2)
		usage("Invalid number of arguments");

	{
		const char *const action = argv[1];
		Success(*function) (Stream, Connection_Id);
		Connection_Id conn_id;

		int port;

		if (!strcmp(action, "--version")) {
			printf("spdsend %s\n", SPDSEND_VERSION);
			exit(EXIT_OK);
		}

		const int action_is_open = strcmp(action, "--open") == 0;
		if (action_is_open) {
			if (argc != 4)
				usage("Invalid number of arguments");
			host = argv[2];
			port = string_to_number(argv[3], 0, 65535);
		} else {
			if (argc != 3)
				usage("Invalid number of arguments");
			conn_id = string_to_number(argv[2], CONNECTION_ID_MIN,
						   CONNECTION_ID_MAX);
			if (!strcmp(action, "--close"))
				function = close_connection;
			else if (!strcmp(action, "--send"))
				function = send_command;
			else
				usage("Invalid option");
		}

		{
			Stream server = open_server();
			if (server == NONE)
				return EXIT_ERROR;

			{
				int result = (action_is_open
					      ? open_connection(server, host,
								port)
					      : function(server, conn_id));
				return (result == OK ? EXIT_OK : EXIT_ERROR);
			}
		}
	}
}


/*
 * common.c - Common utilities
 * Copyright (C) 2003,2006, 2007 Brailcom, o.p.s.
 *
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1, or (at your option) any later
 * version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include <signal.h>
#include <pthread.h>

#include "common.h"

/* This is the same as pthread_create, but blocks all signals in the created
 * thread. */
int spd_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg)
{
	int retsig, ret;
	sigset_t all_signals;
	sigset_t old_signals;

	retsig = sigfillset(&all_signals);
	if (retsig != 0)
		MSG(1, "Can't fill signal set (%d), expect problems when terminating!\n", retsig);
	else {
		retsig = pthread_sigmask(SIG_BLOCK, &all_signals, &old_signals);

	ret = pthread_create(thread, attr, start_routine, arg);

	if (retsig == 0)
		pthread_sigmask(SIG_SETMASK, &old_signals, NULL);

	return ret;
}

void set_speaking_thread_parameters(void)
{
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
}

		if (retsig != 0)
			MSG(1, "Can't set signal set (%d), expect problems when terminating!\n", retsig);


/*************************************************************************/
/*                                                                       */
/*                Centre for Speech Technology Research                  */
/*           Copyright (c) 1999 University of Edinburgh, UK              */
/*                        All Rights Reserved.                           */
/*                                                                       */
/*  Permission is hereby granted, free of charge, to use and distribute  */
/*  this software and its documentation without restriction, including   */
/*  without limitation the rights to use, copy, modify, merge, publish,  */
/*  distribute, sublicense, and/or sell copies of this work, and to      */
/*  permit persons to whom this work is furnished to do so, subject to   */
/*  the following conditions:                                            */
/*   1. The code must retain the above copyright notice, this list of    */
/*      conditions and the following disclaimer.                         */
/*   2. Any modifications must be clearly marked as such.                */
/*   3. Original authors' names are not deleted.                         */
/*   4. The authors' names are not used to endorse or promote products   */
/*      derived from this software without specific prior written        */
/*      permission.                                                      */
/*                                                                       */
/*  THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK        */
/*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
/*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
/*  SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE     */
/*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
/*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
/*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
/*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
/*  THIS SOFTWARE.                                                       */
/*                                                                       */
/*************************************************************************/
/*             Author :  Alan W Black (awb@cstr.ed.ac.uk)                */
/*             Date   :  March 1999                                      */
/*             Modified: Hynek Hanke (hanke@brailcom.org) (2003-2005)    */
/*-----------------------------------------------------------------------*/
/*                                                                       */
/* Client end of Festival server API in C designed specifically formerly */
/* for Galaxy Communicator use, but rewritten to suit Speech Dispatcher  */
/* needs. Please look also at the original festival_client.c library     */
/* that can be found in festival/examples/festival_client.c -- it will   */
/* be probably more up-to-date.                                          */
/*                                                                       */
/* This can be also compiled as a stand-alone program for testing        */
/* purposes:                                                             */
/*    gcc -o festival_client -DSTANDALONE festival_client.c              */
/* and run as:                                                           */
/*    ./festival_client                                                  */
/* This creates a file test.snd, containing the synthesized waveform     */
/* You can run for example:                                              */
/*    play test.snd                                                      */
/* to hear the message                                                   */
/*=======================================================================*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>

#include <glib.h>

/* I'm including my local .h, not the Alan's one! */
#include "festival_client.h"

#include "module_utils.h"

/* For testing endianness */
int fapi_endian_loc = 1;

int festival_connection_crashed;

static char *socket_receive_file_to_buff(int fd, int *size);

/* --- MANAGING FT STRUCTURES --- */

void delete_FT_Wave(FT_Wave * wave)
{
	if (wave != 0) {
		if (wave->samples != 0)
			g_free(wave->samples);
		g_free(wave);
	}
}

int save_FT_Wave_snd(FT_Wave * wave, const char *filename)
{
	FILE *fd;
	struct {
		unsigned int magic;	/* magic number */
		unsigned int hdr_size;	/* size of this header */
		int data_size;	/* length of data (optional) */
		unsigned int encoding;	/* data encoding format */
		unsigned int sample_rate;	/* samples per second */
		unsigned int channels;	/* number of interleaved channels */
	} header;
	short sw_short;
	int i;

	if ((filename == 0) ||
	    (strcmp(filename, "stdout") == 0) || (strcmp(filename, "-") == 0))
		fd = stdout;
	else if ((fd = fopen(filename, "wb")) == NULL) {
		fprintf(stderr,
			"save_FT_Wave: can't open file \"%s\" for writing\n",
			filename);
		return -1;
	}

	header.magic = (unsigned int)0x2e736e64;
	header.hdr_size = sizeof(header);
	header.data_size = 2 * wave->num_samples;
	header.encoding = 3;	/* short */
	header.sample_rate = wave->sample_rate;
	header.channels = 1;
	if (FAPI_LITTLE_ENDIAN) {
		/* snd is always sparc/68000 byte order */
		header.magic = SWAPINT(header.magic);
		header.hdr_size = SWAPINT(header.hdr_size);
		header.data_size = SWAPINT(header.data_size);
		header.encoding = SWAPINT(header.encoding);
		header.sample_rate = SWAPINT(header.sample_rate);
		header.channels = SWAPINT(header.channels);
	}

	/* write header */
	if (fwrite(&header, sizeof(header), 1, fd) != 1) {
		if (fd != stdout)
			fclose(fd);
		return -1;
	}
	if (FAPI_BIG_ENDIAN)
		fwrite(wave->samples, sizeof(short), wave->num_samples, fd);
	else {
		/* have to swap */
		for (i = 0; i < wave->num_samples; i++) {
			sw_short = SWAPSHORT(wave->samples[i]);
			fwrite(&sw_short, sizeof(short), 1, fd);
		}
	}

	if (fd != stdout)
		fclose(fd);
	return 0;
}

void delete_FT_Info(FT_Info * info)
{
	if (info != 0)
		g_free(info);
}

/* --- FESTIVAL REPLY PARSING --- */

static int nist_get_param_int(char *hdr, char *field, int def_val)
{
	char *p;
	int val;

	if (((p = strstr(hdr, field)) != NULL) &&
	    (strncmp(" -i ", p + strlen(field), 4) == 0)) {
		sscanf(p + strlen(field) + 4, "%d", &val);
		return val;
	} else
		return def_val;
}

static int nist_require_swap(char *hdr)
{
	char *p;
	char *field = "sample_byte_format";

	if ((p = strstr(hdr, field)) != NULL) {
		if (((strncmp(" -s2 01", p + strlen(field), 7) == 0)
		     && FAPI_BIG_ENDIAN)
		    || ((strncmp(" -s2 10", p + strlen(field), 7) == 0)
			&& FAPI_LITTLE_ENDIAN))
			return 1;
	}
	return 0;		/* if unknown assume native byte order */
}

/* --- FESTIVAL SOCKET MANIPULATION --- */

/* Return an FD to a remote server */
static int festival_socket_open(const char *host, int port)
{
	struct sockaddr_in serv_addr;
	struct hostent *serverhost;
	int fd;

	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (fd < 0) {
		fprintf(stderr, "festival_client: can't get socket\n");
		return -1;
	}
	memset(&serv_addr, 0, sizeof(serv_addr));
	if ((serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) {
		/* its a name rather than an ipnum */
		serverhost = gethostbyname(host);
		if (serverhost == (struct hostent *)0) {
			fprintf(stderr,
				"festival_client: gethostbyname failed\n");
			close(fd);
			return -1;
		}
		memmove(&serv_addr.sin_addr, serverhost->h_addr,
			serverhost->h_length);
	}
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);

	if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) {
		fprintf(stderr, "festival_client: connect to server failed\n");
		close(fd);
		return -1;
	}

	return fd;
}

/* Receive file (probably a waveform file) from socket using   */
/* Festival key stuff technique, but long winded I know, sorry */
/* but will receive any file without closing the stream or     */
/* using OOB data                                              */
static char *socket_receive_file_to_buff(int fd, int *size)
{
	static char *file_stuff_key = "ft_StUfF_key";	/* must == Festival's key */
	char *buff;
	int bufflen;
	int n, k, i;
	char c;

	if (fd < 0)
		return NULL;

	bufflen = 1024;
	buff = (char *)g_malloc(bufflen);
	*size = 0;

	for (k = 0; file_stuff_key[k] != '\0';) {
		n = read(fd, &c, 1);
		if (n <= 0) {
			DBG("ERROR: FESTIVAL CLOSED CONNECTION (1)");
			close(fd);
			festival_connection_crashed = 1;
			g_free(buff);
			return NULL;	/* hit stream eof before end of file */
		}

		if ((*size) + k + 1 >= bufflen) {
			/* +1 so you can add a NULL if you want */
			bufflen += bufflen / 4;
			buff = (char *)g_realloc(buff, bufflen);
		}
		if (file_stuff_key[k] == c)
			k++;
		else if ((c == 'X') && (file_stuff_key[k + 1] == '\0')) {
			/* It looked like the key but wasn't */
			for (i = 0; i < k; i++, (*size)++)
				buff[*size] = file_stuff_key[i];
			k = 0;
			/* omit the stuffed 'X' */
		} else {
			for (i = 0; i < k; i++, (*size)++)
				buff[*size] = file_stuff_key[i];
			k = 0;
			buff[*size] = c;
			(*size)++;
		}

	}

	return buff;
}

static char *client_accept_s_expr(int fd)
{
	/* Read s-expression from server, as a char * */
	char *expr;
	int filesize;

	if (fd < 0)
		return NULL;

	expr = socket_receive_file_to_buff(fd, &filesize);
	expr[filesize] = '\0';
	return expr;
}

static FT_Wave *client_accept_waveform(int fd, int *stop_flag,
				       int stop_by_close)
{
	/* Read waveform from server */
	char *wavefile;
	int filesize;
	int num_samples, sample_rate, i;
	FT_Wave *wave;

	if (fd < 0)
		return NULL;

	wavefile = socket_receive_file_to_buff(fd, &filesize);
	if (wavefile == NULL)
		return NULL;

	wave = NULL;

	/* I know this is NIST file and its an error if it isn't */
	if (filesize >= 1024) {
		/* If this doesn't work, probably you forgot to set
		   the output file type to NIST ! by Parameter.set */
		num_samples = nist_get_param_int(wavefile, "sample_count", 1);
		sample_rate =
		    nist_get_param_int(wavefile, "sample_rate", 16000);

		if ((num_samples * sizeof(short)) + 1024 == filesize) {
			wave = (FT_Wave *) g_malloc(sizeof(FT_Wave));
			DBG("Number of samples from festival: %d", num_samples);
			wave->num_samples = num_samples;
			wave->sample_rate = sample_rate;
			if (num_samples != 0) {
				wave->samples =
				    (short *)g_malloc(num_samples *
						      sizeof(short));
				memmove(wave->samples, wavefile + 1024,
					num_samples * sizeof(short));
				if (nist_require_swap(wavefile))
					for (i = 0; i < num_samples; i++)
						wave->samples[i] =
						    SWAPSHORT(wave->samples[i]);
			} else {
				wave->samples = NULL;
			}
		}
	}

	g_free(wavefile);

	return wave;
}

int festival_get_ack(FT_Info ** info, char *ack)
{
	int read_bytes;
	int n;

	if (*info == NULL)
		return -1;
	if ((*info)->server_fd < 0)
		return -1;

	for (n = 0; n < 3;) {
		read_bytes = read((*info)->server_fd, ack + n, 3 - n);
		if (read_bytes <= 0) {
			/* WARNING: This is a very strange situation
			   but it happens often, I don't really know
			   why??? */
			DBG("ERROR: FESTIVAL CLOSED CONNECTION (2)");
			close((*info)->server_fd);
			festival_connection_crashed = 1;
			return -1;
		}
		n += read_bytes;
	}
	ack[3] = '\0';
	return 0;
}

int festival_read_response(FT_Info * info, char **expr)
{
	char buf[4];
	char *r;

	DBG("Com: Reading response");

	if (info == NULL)
		return 1;
	if (info->server_fd < 0)
		return 1;

	if (festival_get_ack(&info, buf))
		return 1;
	buf[3] = 0;

	DBG("<- Festival: |%s|", buf);

	if (!strcmp(buf, "ER\n")) {
		return 1;
	}

	r = client_accept_s_expr(info->server_fd);
	if (expr != NULL) {
		*expr = r;
	} else if (r != NULL) {
		g_free(r);
	}

	if (festival_get_ack(&info, buf)) {
		if (expr)
			g_free(*expr);
		return 1;
	}
	DBG("<- Festival: |%s|", buf);

	return 0;
}

int festival_accept_any_response(FT_Info * info)
{
	char ack[4];
	int r;
	char *expr;

	DBG("Com: Accepting any response");
	do {
		if ((r = festival_get_ack(&info, ack)))
			return r;
		DBG("<- Festival: |%s|", ack);
		if (strcmp(ack, "WV\n") == 0) {	/* receive a waveform */
			client_accept_waveform(info->server_fd, NULL, 0);
		} else if (strcmp(ack, "LP\n") == 0) {	/* receive an s-expr */
			expr = client_accept_s_expr(info->server_fd);
			if (expr != NULL)
				g_free(expr);
		} else if (strcmp(ack, "ER\n") == 0) {	/* server got an error */
			/* This message ER is returned even if it was because there was
			   no sound produced, for this reason, the warning is disabled */
			/* fprintf(stderr,"festival_client: server returned error\n"); */
			break;
		}
	} while (strcmp(ack, "OK\n") != 0);

	return 0;
}

/* --- HELPER FUNCTIONS --- */
int festival_check_info(FT_Info * info, const char *fnname)
{
	assert(fnname != NULL);
	if ((info == NULL) || (info->server_fd == -1)) {
		DBG("%s called with info = NULL or server_fd == -1\n", fnname);
		return -1;
	}
	return 0;
}

/***********************************************************************/
/* Public Functions to this API                                        */
/***********************************************************************/

/* Opens a connection to Festival server (which must be running)
 * and returns it's identification in new FT_Info */
FT_Info *festivalOpen(FT_Info * info)
{
	char *resp;
	int ret;

	DBG("Opening socket fo Festival server");

	festival_connection_crashed = 0;

	if (info == 0)
		info = festivalDefaultInfo();

	info->server_fd =
	    festival_socket_open(info->server_host, info->server_port);

	if (info->server_fd == -1) {
		delete_FT_Info(info);
		festival_connection_crashed = 1;
		return NULL;
	}

	FEST_SEND_CMD("(require 'speech-dispatcher)");
	ret = festival_read_response(info, &resp);
	if (ret || resp == NULL || strcmp(resp, "t\n")) {
		DBG("ERROR: Can't load speech-dispatcher module into Festival."
		    "Reason: %s", resp);
		delete_FT_Info(info);
		if (!ret && resp)
			g_free(resp);
		return NULL;
	}
	g_free(resp);
	resp = NULL;

	FEST_SEND_CMD("(Parameter.set 'Wavefiletype 'nist)\n");
	ret = festival_read_response(info, &resp);
	if (ret || resp == NULL || strcmp(resp, "nist\n")) {
		DBG("ERROR: Can't set Wavefiletype to nist in Festival. Reason: %s", resp);
		delete_FT_Info(info);
		if (!ret && resp)
			g_free(resp);
		return NULL;
	}
	g_free(resp);

	return info;
}

int
festival_speak_command(FT_Info * info, char *command, const char *text,
		       int symbol, int resp)
{
	FILE *fd;
	const char *p;
	char *str;
	int ret;

	if (festival_check_info(info, "festival_speak_command") == -1)
		return -1;
	if (command == NULL)
		return -1;
	if (text == NULL)
		return -1;

	DBG("(festival_speak_command): %s", text);

	/* Opens a stream associated to the socket */
	fd = fdopen(dup(info->server_fd), "wb");

	/* Send the command and data */
	if (symbol == 0)
		str = g_strdup_printf("(%s \"", command);
	else
		str = g_strdup_printf("(%s '", command);
	fputs(str, fd);
	/* Copy text over to server, escaping any quotes */
	for (p = text; p && (*p != '\0'); p++) {
		if ((*p == '"') || (*p == '\\'))
			putc('\\', fd);
		putc(*p, fd);
	}
	if (symbol == 0)
		fprintf(fd, "\")\n");
	else
		fprintf(fd, ")\n");

	DBG("-> Festival: escaped text is %s", text);
	DBG("-> Festival: |%sthe text is displayed above\")|", str);

	g_free(str);
	/* Close the stream (but not the socket) */
	fclose(fd);
	DBG("Resources freed");

	if (resp) {
		ret = festival_read_response(info, NULL);
		if (ret) {
			DBG("ERROR: Festival reported error in speak command);");
			return -1;
		}
	}

	return 0;
}

#define FEST_SPEAK_CMD(name, cmd, symbol, resp) \
	int \
	name(FT_Info *info, const char *text) \
	{ \
		return festival_speak_command(info, cmd, text, symbol, resp); \
	}

/* Sends a TEXT to Festival server for synthesis. Doesn't
 * wait for reply (see festivalStringToWaveGetData()).
 * Please make sure that the socket is empty before calling
 * this command -- otherwise, you would get another message
 * in response.
 * Returns 0 if everything is ok, -1 otherwise.
*/
FEST_SPEAK_CMD(festivalStringToWaveRequest, "speechd-speak-ssml", 0, 1)
    FEST_SPEAK_CMD(festivalSpell, "speechd-spell", 0, 1)
    FEST_SPEAK_CMD(festivalSoundIcon, "speechd-sound-icon", 1, 0)
    FEST_SPEAK_CMD(festivalCharacter, "speechd-character", 0, 0)
    FEST_SPEAK_CMD(festivalKey, "speechd-key", 0, 0)

/* Reads the wavefile sent back after festivalStringToWaveRequest()
 * has been called. This function blocks until all the data is
 * available. Note that for longer messages this can be quite long
 * on some slower machines. */
FT_Wave *festivalStringToWaveGetData(FT_Info * info)
{
	FT_Wave *wave = NULL;
	char ack[5];
	char *expr;

	/* Read back info from server */
	/* This assumes only one waveform will come back, also LP is unlikely */
	do {
		if (festival_get_ack(&info, ack))
			return NULL;
		DBG("<- Festival: %s", ack);
		if (strcmp(ack, "WV\n") == 0) {
			wave = client_accept_waveform(info->server_fd, NULL, 0);
		} else if (strcmp(ack, "LP\n") == 0) {
			expr = client_accept_s_expr(info->server_fd);
			if (expr != NULL)
				g_free(expr);
		} else if (strcmp(ack, "ER\n") == 0) {
			//  fprintf(stderr,"festival_client: server returned error\n");
			break;
		}
	} while (strcmp(ack, "OK\n") != 0);

	return wave;
}

FT_Wave *festivalGetDataMulti(FT_Info * info, char **callback, int *stop_flag,
			      int stop_by_close)
{
	FT_Wave *wave = NULL;
	char ack[5];
	char *resp = NULL;
	FILE *fd;

	/* This assumes only one waveform will come back */
	wave = NULL;

	*callback = NULL;

	DBG("Stop by close mode : %d", stop_by_close);

	DBG("-> Festival: (speechd-next)");
	fd = fdopen(dup(info->server_fd), "wb");
	fprintf(fd, "(speechd-next)\n");
	fflush(fd);
	fclose(fd);

	do {
		if (festival_get_ack(&info, ack)) {
			DBG("Get ack failed");
			g_free(resp);
			return NULL;
		}
		DBG("<- Festival: %s", ack);

		if (strcmp(ack, "WV\n") == 0) {
			wave =
			    client_accept_waveform(info->server_fd, stop_flag,
						   stop_by_close);
		} else if (strcmp(ack, "LP\n") == 0) {
			g_free(resp);
			resp = client_accept_s_expr(info->server_fd);
			if (resp == NULL) {
				DBG("ERROR: Something wrong in communication with Festival, s_expr = NULL");
				return NULL;
			}
			if (strlen(resp) != 0)
				resp[strlen(resp) - 1] = 0;
			DBG("<- Festival: |%s|", resp);
			if (!strcmp(resp, "nil")) {
				DBG("festival_client: end of samples\n");
				g_free(resp);
				wave = NULL;
				resp = NULL;
			}
		} else if (strcmp(ack, "ER\n") == 0) {
			DBG("festival_client: server returned error\n");
			g_free(resp);
			return NULL;
		}
	} while (strcmp(ack, "OK\n") != 0);

	if (resp) {
		if ((strlen(resp) > 0) && (resp[0] != '#'))
			*callback = resp;
		else
			g_free(resp);
	}

	return wave;
}

/* Closes the Festival server socket connection */
int festivalClose(FT_Info * info)
{
	if (info == 0)
		return 0;

	if (info->server_fd != -1) {
		FILE *fd;
		fd = fdopen(dup(info->server_fd), "wb");
		if (fd != NULL) {
			fprintf(fd, "(quit)\n");
			fclose(fd);
		}
		close(info->server_fd);
	}

	return 0;
}

/* --- INFORMATION RETRIEVAL COMMANDS --- */

char **lisp_list_get_vect(const char *expr)
{
	size_t len;
	char *helper;
	gchar **vect;
	size_t i, j;

	len = strlen(expr);
	helper = g_malloc(sizeof(char) * (len + 1));

	//Remove parenthesis
	j = 0;
	for (i = 0; i < len; i++) {
		if ((expr[i] != '(') && (expr[i] != ')')) {
			helper[j] = expr[i];
			j++;
		}
	}
	helper[j] = '\0';

	// Split into a vector of atoms
	vect = g_strsplit(helper, " ", 0);
	g_free(helper);

	return vect;
}

char *vect_read_item(char **vect, char *field)
{
	int i;

	for (i = 0;; i++) {
		if (vect[i] == NULL)
			return NULL;
		else {
			if (!strcmp(vect[i], field)) {
				if (vect[i + 1] != NULL)
					return vect[i + 1];
				else
					return NULL;
			}
		}
	}
}

FT_Info *festivalDefaultInfo()
{
	FT_Info *info;
	info = (FT_Info *) g_malloc(sizeof(FT_Info));

	info->server_host = FESTIVAL_DEFAULT_SERVER_HOST;
	info->server_port = FESTIVAL_DEFAULT_SERVER_PORT;
	info->text_mode = FESTIVAL_DEFAULT_TEXT_MODE;

	info->server_fd = -1;

	return info;
}

/* For testing purposes, this library can be compiled as
 * a standalone program, please see the introduction at
 * the beginning  of this file
 */

#ifdef STANDALONE
int main(int argc, char **argv)
{
	char *server = 0;
	int port = -1;
	char *text = 0;
	char *output = 0;
	char *mode = 0;
	int i;
	FT_Info *info;
	FT_Wave *wave;

	printf("Welcome to Festival client library for Speech Dispatcher\n");

	info = festivalDefaultInfo();
	if (server != 0)
		info->server_host = FESTIVAL_DEFAULT_SERVER_HOST;
	if (port != -1)
		info->server_port = FESTIVAL_DEFAULT_SERVER_PORT;
	if (mode != 0)
		info->text_mode = FESTIVAL_DEFAULT_TEXT_MODE;

	info = festivalOpen(info);

	if (info == 0) {
		printf("Can't open connection to festival server!\n");
		exit(1);
	}
	if (info->server_fd <= 0) {
		printf("Can't open connection to festival server!\n");
		exit(1);
	}

	festivalStringToWaveRequest(info,
				    "Hi, how are you? I'm Festival! And who are you?");
	wave = festivalStringToWaveGetData(info);

	if (wave != 0) {
		save_FT_Wave_snd(wave, "test.snd");
	} else {
		printf("Wave null! Festival server doesn't work properly.\n");
		exit(1);
	}
	festivalClose(info);

	printf("The synthesized text should have been written to test.snd\n");

	return 0;
}
#endif

	if (festival_check_info(info, "festival_speak_command") == -1) {
		return NULL;
	}


/*
 * ibmtts_shim.c - Shim for IBM TTS (Voxin, version < 3)
 * to be able to build the ibmtts module without the IBM TTS SDK.
 *
 * Copyright (C) 2019 Samuel Thibault <samuel.thibault@ens-lyon.org>
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "eci.h"
#include <assert.h>

ECIHand ECIFNDECLARE eciNew(void) {
	assert(0);
}

int ECIFNDECLARE eciGetAvailableLanguages(enum ECILanguageDialect *aLanguages, int *nLanguages) {
	assert(0);
}

ECIHand ECIFNDECLARE eciDelete(ECIHand hEngine) {
	assert(0);
}

void ECIFNDECLARE eciVersion(char *pBuffer) {
	assert(0);
}

void ECIFNDECLARE eciErrorMessage(ECIHand hEngine, void* buffer) {
	assert(0);
}

int ECIFNDECLARE eciGetParam(ECIHand hEngine, enum ECIParam Param) {
	assert(0);
}

int ECIFNDECLARE eciSetParam(ECIHand hEngine, enum ECIParam Param, int iValue) {
	assert(0);
}

Boolean ECIFNDECLARE eciGetVoiceName(ECIHand hEngine, int iVoice, void *pBuffer) {
	assert(0);
}

	assert(0);
}

int ECIFNDECLARE eciSetVoiceParam(ECIHand hEngine, int iVoice, enum ECIVoiceParam Param, int iValue) {
	assert(0);
}

Boolean ECIFNDECLARE eciAddText(ECIHand hEngine, ECIInputText pText) {
	assert(0);
}

Boolean ECIFNDECLARE eciInsertIndex(ECIHand hEngine, int iIndex) {
	assert(0);
}

Boolean ECIFNDECLARE eciSynthesize(ECIHand hEngine) {
	assert(0);
}

Boolean ECIFNDECLARE eciStop(ECIHand hEngine) {
	assert(0);
}

Boolean ECIFNDECLARE eciSynchronize(ECIHand hEngine) {
	assert(0);
}

Boolean ECIFNDECLARE eciSetOutputBuffer(ECIHand hEngine, int iSize, short *psBuffer) {
	assert(0);
}

void ECIFNDECLARE eciRegisterCallback(ECIHand hEngine, ECICallback Callback, void *pData) {
	assert(0);
}

ECIDictHand ECIFNDECLARE eciNewDict(ECIHand hEngine) {
	assert(0);
}

ECIDictHand ECIFNDECLARE eciGetDict(ECIHand hEngine) {
	assert(0);
}

enum ECIDictError ECIFNDECLARE eciSetDict(ECIHand hEngine, ECIDictHand hDict) {
	assert(0);
}

ECIDictHand ECIFNDECLARE eciDeleteDict(ECIHand hEngine, ECIDictHand hDict) {
	assert(0);
}

enum ECIDictError ECIFNDECLARE eciLoadDict(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText pFilename) {
	assert(0);
}

Boolean ECIFNDECLARE eciCopyVoice(ECIHand hEngine, int iVoiceFrom, int iVoiceTo) {
	assert(0);
}


/*
 * module_process.c - Processing loop of output modules.
 *
 * Copyright (C) 2020-2023, 2025 Samuel Thibault <samuel.thibault@ens-lyon.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY Samuel Thibault AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <pthread.h>

#include <spd_audio.h>
#include "spd_module_main.h"

pthread_mutex_t module_stdout_mutex = PTHREAD_MUTEX_INITIALIZER;

static int module_should_stop;

/* This sends some text to the server, taking the mutex to avoid intermixing
 * between multi-line answers and asynchronous sends.  */
void module_send(const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	pthread_mutex_lock(&module_stdout_mutex);
	vprintf(format, ap);
	pthread_mutex_unlock(&module_stdout_mutex);
	va_end(ap);
	fflush(stdout);
}

/* Whether we will send the audio to the server */
static int audio_server;

void module_audio_set_server(void)
{
	audio_server = 1;
}

static int module_audio_set_through_server(const char *cur_item, const char *cur_value) {
	if (strcmp(cur_item, "audio_output_method") != 0)
		/* We only support the audio output method parameter */
		return -1;

	if (strcmp(cur_value, "server") != 0)
		/* We only support server audio output method */
		return -1;

	return 0;
}

static void module_tts_output_send_server(const AudioTrack *track, AudioFormat format)
{
	const char *p, *end;
	size_t size = track->num_channels * track->num_samples * track->bits / 8;

	pthread_mutex_lock(&module_stdout_mutex);
	printf("705-bits=%d\n", track->bits);
	printf("705-num_channels=%d\n", track->num_channels);
	printf("705-sample_rate=%d\n", track->sample_rate);
	printf("705-num_samples=%d\n", track->num_samples);
	printf("705-big_endian=%d\n", format);

	printf("705-AUDIO");
	putc(0, stdout);

	p = (const char *) track->samples;
	end = p + size;

	/* HDLC escaping: prefix NL and escapes with escape, and invert their bit 5. */
	const char escape = 0x7d;
	const char invert = 1<<5;

	while (p < end) {
		const char *stop, *nl, *next;

		stop = memchr(p, escape, end - p);
		nl = memchr(p, '\n', end - p);

		if (nl && (!stop || nl < stop))
			stop = nl;

		if (stop) {
			next = stop+1;
		} else {
			next = stop = end;
		}

		fwrite(p, 1, stop - p, stdout);

		/* Escape NL or escape */
		if (stop < end) {
			putc(escape, stdout);
			putc((*stop) ^ invert, stdout);
		}

		p = next;
	}
	putc('\n', stdout);
	printf("705 AUDIO\n");

	pthread_mutex_unlock(&module_stdout_mutex);
	fflush(stdout);
}

/* Arbitrary chunk size in bytes, large enough to get efficient transfer
 * but small enough to be reactive. */
#define MAX_CHUNK 10000
void module_tts_output_server(const AudioTrack *track, AudioFormat format)
{
	AudioTrack mytrack = *track;
	size_t sample_size = track->num_channels * track->bits / 8;
	int samplepos = 0;
	int num_samples;

	while (samplepos < track->num_samples) {
		if (module_should_stop)
			/* We are requested to stop, ignore the rest of audio */
			break;

		num_samples = MAX_CHUNK / sample_size;
		if (num_samples > track->num_samples - samplepos)
			num_samples = track->num_samples - samplepos;

		mytrack.num_samples = num_samples;
		mytrack.samples = (void*) track->samples + samplepos * sample_size;
		samplepos += num_samples;

		module_tts_output_send_server(&mytrack, format);

		module_process(STDIN_FILENO, 0);
	}
}

/*
 * This only parses the SSIP protocol from the server, and calls the
 * corresponding functions provided by the module or by module_utils.c
 */

#define print(fmt, ...) module_send(fmt "\n", ## __VA_ARGS__)

#define BAD_SYNTAX "302 ERROR BAD SYNTAX"
#define BAD_PARAM "303 ERROR INVALID PARAMETER OR VALUE"
#define BAD_MULTILINE "305 DATA MORE THAN ONE LINE"

#define bad_syntax() print(BAD_SYNTAX)
#define bad_param() print(BAD_PARAM)
#define bad_multiline() print(BAD_MULTILINE)

#define bad_internal() print("401 ERROR INTERNAL")
#define bad_memory() print("402 ERROR OUT OF MEMORY")

/* some text
 * at will
 * .
 */
static void cmd_speak(int fd, SPDMessageType msgtype)
{
	size_t text_allocated = 128, new_allocated;
	char  *text = malloc(text_allocated), *new_text;
	size_t text_len = 0;
	size_t len;
	int ret;
	int nlines = 0;

	print("202 OK RECEIVING MESSAGE");

	while (1) {
		char *line = module_readline(fd, 1);
		int offset = 0;
		if (!line) {
			/* EOF */
			free(text);
			return;
		}

		if (!strcmp(line, ".\n")) {
			/* Replace \n at the end with a \0 */
			if (text_len) {
				text_len--;
				text[text_len] = 0;
			}
			free(line);
			break;
		}

		if (line[0] == '.') {
			offset++;
			line++;
		}

		nlines++;
		len = strlen(line);

		new_allocated = text_allocated;
		while (text_len + len > new_allocated)
			new_allocated *= 2;

		if (new_allocated > text_allocated) {
			new_text = realloc(text, new_allocated);
			if (!new_text) {
				free(line);
				free(text);
				bad_internal();
				return;
			}
			text = new_text;
			text_allocated = new_allocated;
		}
		memcpy(text + text_len, line, len);
		text_len += len;
		free(line - offset);
	}

	if (!text_len) {
		free(text);
		print("301 ERROR CANT SPEAK");
		return;
	}

	if (msgtype != SPD_MSGTYPE_TEXT && nlines > 1) {
		free(text);
		print("305 DATA MORE THAN ONE LINE");
		return;
	}

	if (msgtype == SPD_MSGTYPE_KEY || msgtype == SPD_MSGTYPE_CHAR) {
		if (!strcmp(text, "space")) {
			free(text);
			text = strdup(" ");
			text_len = 1;
		}
	}

	module_should_stop = 0;

#pragma weak module_speak_sync
#pragma weak module_speak
	if (module_speak_sync) {
		module_speak_sync(text, text_len, msgtype);
	} else {
		pthread_mutex_lock(&module_stdout_mutex);
		ret = module_speak(text, text_len, msgtype);
		if (ret > 0)
			printf("200 OK SPEAKING\n");
		else
			printf("301 ERROR CANT SPEAK\n");
		fflush(stdout);
		pthread_mutex_unlock(&module_stdout_mutex);
	}
	free(text);
}

static void cmd_speak_text(int fd)
{
	return cmd_speak(fd, SPD_MSGTYPE_TEXT);
}

static void cmd_speak_sound_icon(int fd)
{
	return cmd_speak(fd, SPD_MSGTYPE_SOUND_ICON);
}

static void cmd_speak_char(int fd)
{
	return cmd_speak(fd, SPD_MSGTYPE_CHAR);
}

static void cmd_speak_key(int fd)
{
	return cmd_speak(fd, SPD_MSGTYPE_KEY);
}

void module_speak_ok(void)
{
	print("200 OK SPEAKING");
}

void module_speak_error(void)
{
	print("301 ERROR CANT SPEAK");
}

static void cmd_stop(void)
{
	module_should_stop = 1;
	module_stop();
}

static void cmd_pause(void)
{
	module_should_stop = 1;
	module_pause();
}

static void cmd_list_voices(char *line)
{
	SPDVoice **voices, **voice;
	int one = 0;;
	char *dumb;
	char *requested_language;
	char *requested_variant = NULL;
	char *save = NULL;

	voices = module_list_voices();
	if (!voices) {
		print("304 CANT LIST VOICES");
		return;
	}

	dumb = strtok_r(line, " \n", &save);
	if (strcmp(dumb, "LIST")) {
		bad_internal();
		return;
	}
	dumb = strtok_r(NULL, " \n", &save);
	if (strcmp(dumb, "VOICES")) {
		bad_internal();
		return;
	}
	requested_language = strtok_r(NULL, " \n", &save);
	if (requested_language)
		requested_variant = strtok_r(NULL, " \n", &save);

	pthread_mutex_lock(&module_stdout_mutex);
	for (voice = voices; *voice; voice++) {
		const char *name = (*voice)->name;
		const char *language = (*voice)->language;
		const char *variant = (*voice)->variant;

		if (!name)
			/* Ok, skip this */
			continue;

		if (!language)
			language = "none";
		if (!variant)
			variant = "none";

		if (requested_language) {
			if (strcasecmp(requested_language, language))
			{
				/* Not exactly the requested locale, but maybe the language? */
				const char *dash = strchr(language, '-');
				size_t langlen = dash - language;

				if (strlen(requested_language) != langlen
				    || strncasecmp(requested_language, language, langlen))
					/* Not the requested language */
					continue;
			}
			if (requested_variant)
				if (strcasecmp(requested_variant, variant))
					/* Not the requested variant, skip */
					continue;
		}

		one = 1;

		printf("200-%s\t%s\t%s\n", name, language, variant);
	}
	if (one)
		printf("200 OK VOICE LIST SENT\n");
	else
		printf("304 CANT LIST VOICES\n");
	pthread_mutex_unlock(&module_stdout_mutex);
	fflush(stdout);
}

/* FOO1=bar1
 * FOO2=bar2
 * .
 */
static int cmd_params(int fd, int ack, const char *type, int (*set)(const char *var, const char *val))
{
	char *var, *val, *save;

	print("%u OK RECEIVING %sSETTINGS", ack, type);

	while (1) {
		char *line = module_readline(fd, 1);
		if (!line)
			/* EOF */
			return -1;

		if (!strcmp(line, ".\n")) {
			free(line);

			if (!err)
				return 0;
			print("%s", err);
			return -1;
		}

		save = NULL;
		var = strtok_r(line, "=", &save);
		if (!var) {
			err = BAD_SYNTAX;
			free(line);
			continue;
		}

		val = strtok_r(NULL, "\n", &save);
		if (!val) {
			err = BAD_SYNTAX;
			free(line);
			continue;
		}

		if (set(var, val) != 0)
			err = BAD_PARAM;

		free(line);
	}
}

static void cmd_set(int fd)
{
	if (cmd_params(fd, 203, "", module_set) != 0)
		return;

	print("203 OK SETTINGS RECEIVED");
}

static void cmd_audio(int fd)
{
	char *status = NULL;
	int ret;

	if (audio_server) {
		if (cmd_params(fd, 207, "AUDIO ", module_audio_set_through_server) != 0)
			return;

		ret = 0;
	} else {
		if (cmd_params(fd, 207, "AUDIO ", module_audio_set) != 0)
			return;

		ret = module_audio_init(&status);
	}

	if (!ret)
		print("203 OK AUDIO INITIALIZED");
	else
		print("300-%s\n300 MODULE ERROR", status);

	free(status);
}

static void cmd_loglevel(int fd)
{
	if (cmd_params(fd, 207, "LOGLEVEL ", module_loglevel_set) != 0)
		return;
	print("203 OK LOGLEVEL SET");
}

/* DEBUG ON /some/file
 * or
 * DEBUG OFF
 */
static void cmd_debug(char *line)
{
	char *debug, *on, *file = NULL, *save = NULL;
	int enable = 0;

	debug = strtok_r(line, " \n", &save);
	if (!debug) {
		bad_syntax();
		return;
	}
	if (strcmp(debug, "DEBUG")) {
		bad_internal();
		return;
	}

	on = strtok_r(NULL, " \n", &save);
	if (!on) {
		bad_syntax();
		return;
	}

	if (!strcmp(on, "ON")) {
		enable = 1;
		file = strtok_r(NULL, " \n", &save);
		if (!file) {
			bad_syntax();
			return;
		}
	} else if (strcmp(on, "OFF")) {
		bad_syntax();
		return;
	}

	if (module_debug(enable, file) != 0)
		print("303 CANT OPEN CUSTOM DEBUG FILE");
	else
		print("200 OK DEBUGGING %s", on);
}

static void cmd_quit(void)
{
	module_close();

	print("210 OK QUIT");
}

int module_process(int fd, int block)
{
	while (1) {
		char *line = module_readline(fd, block);
		if (line == NULL)
			return -1;

		if (!strcmp(line, "SPEAK\n"))
			cmd_speak_text(fd);

		else if (!strcmp(line, "SOUND_ICON\n"))
			cmd_speak_sound_icon(fd);

		else if (!strcmp(line, "CHAR\n"))
			cmd_speak_char(fd);

		else if (!strcmp(line, "KEY\n"))
			cmd_speak_key(fd);

		else if (!strcmp(line, "STOP\n"))
			cmd_stop();

		else if (!strcmp(line, "PAUSE\n"))
			cmd_pause();

		else if (!strncmp(line, "LIST VOICES", 11))
			cmd_list_voices(line);

		else if (!strcmp(line, "SET\n"))
			cmd_set(fd);

		else if (!strcmp(line, "AUDIO\n"))
			cmd_audio(fd);

		else if (!strcmp(line, "LOGLEVEL\n"))
			cmd_loglevel(fd);

		else if (!strncmp(line, "DEBUG", 5))
			cmd_debug(line);

		else if (!strcmp(line, "QUIT\n")) {
			free(line);
			cmd_quit();
			fflush(stdout);
			return 0;
		}

		else
			print("300 ERR UNKNOWN COMMAND");

		free(line);
		fflush(stdout);
	}
}

/* Report index */
void module_report_index_mark(const char *mark)
{
	if (!mark)
		return;

	print("700-%s\n700 INDEX MARK", mark);
}

/* Report speak start */
void module_report_event_begin(void)
{
	print("701 BEGIN");
}

/* Report speak end */
void module_report_event_end(void)
{
	print("702 END");
}

/* Report speak stop */
void module_report_event_stop(void)
{
	print("703 STOP");
}

/* Report speak pause */
void module_report_event_pause(void)
{
	print("704 PAUSE");
}

/* Report sound icon */
void module_report_icon(const char *icon)
{
	if (!icon)
		return;
	print("706-%s\n706 ICON", icon);
}


/*
 * alloc.c - Auxiliary functions for allocating and freeing data structures
 *
 * Copyright (C) 2001,2002,2003,2004,2005,2007 Brailcom, o.p.s.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "alloc.h"

TFDSetElement spd_fdset_copy(TFDSetElement *old)
{
	TFDSetElement new;

	new = *old;
	new.msg_settings.voice.language =
	    g_strdup(old->msg_settings.voice.language);
	new.msg_settings.voice.name = g_strdup(old->msg_settings.voice.name);
	new.client_name = g_strdup(old->client_name);
	new.output_module = g_strdup(old->output_module);
	new.index_mark = g_strdup(old->index_mark);
	new.audio_output_method = g_strdup(old->audio_output_method);
	new.audio_oss_device = g_strdup(old->audio_oss_device);
	new.audio_alsa_device = g_strdup(old->audio_alsa_device);
	new.audio_nas_server = g_strdup(old->audio_nas_server);
	new.audio_pulse_server = g_strdup(old->audio_pulse_server);
	new.audio_pulse_device = g_strdup(old->audio_pulse_device);

	return new;

}

TSpeechDMessage *spd_message_copy(TSpeechDMessage * old)
{

	if (old == NULL)
		return NULL;

	new = (TSpeechDMessage *) g_malloc(sizeof(TSpeechDMessage));

	*new = *old;
	new->buf = g_malloc((old->bytes + 1) * sizeof(char));
	memcpy(new->buf, old->buf, old->bytes);
	new->buf[new->bytes] = 0;
	new->settings = spd_fdset_copy(&old->settings);

	return new;
}

void mem_free_fdset(TFDSetElement * fdset)
{
	/* Don't forget that only these items are filled in
	   in a TSpeechDMessage */
	g_free(fdset->client_name);
	g_free(fdset->msg_settings.voice.language);
	g_free(fdset->msg_settings.voice.name);
	g_free(fdset->output_module);
	g_free(fdset->index_mark);
	g_free(fdset->audio_output_method);
	g_free(fdset->audio_oss_device);
	g_free(fdset->audio_alsa_device);
	g_free(fdset->audio_nas_server);
	g_free(fdset->audio_pulse_server);
	g_free(fdset->audio_pulse_device);
}

void mem_free_message(TSpeechDMessage * msg)
{
	if (msg == NULL)
		return;
	g_free(msg->buf);
	mem_free_fdset(&(msg->settings));
	g_free(msg);
}


/*
 * history.h - History functions for Speech Dispatcher header
 *
 * Copyright (C) 2001, 2002, 2003 Brailcom, o.p.s.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * $Id: history.h,v 1.11 2006-07-11 16:12:27 hanke Exp $
 */

#ifndef HISTORY_H
#define HISTORY_H

#include "speechd.h"

char *history_get_client_list(void);
char *history_get_message_list(guint client_id, int from, int num);

char *history_cursor_set_last(int fd, guint client_id);
char *history_cursor_set_first(int fd, guint client_id);
char *history_cursor_set_pos(int fd, guint client_id, int pos);
char *history_cursor_next(int fd);
char *history_cursor_prev(int fd);
char *history_cursor_get(int fd);
char *history_cursor_forward(int fd);
char *history_cursor_backward(int fd);
char *history_say_id(int fd, int id);
char *history_get_client_id(int fd);
char *history_get_message(int uid);
int history_add_message(TSpeechDMessage * msg);

/* Internal functions */
GList *get_messages_by_client(int uid);
gint message_compare_id(gconstpointer element, gconstpointer value);

#endif /* HISTORY_H */