<commit_before>#include <iostream>
#include <string>
#include <limits>
#include "consoleui.h"

using namespace std;

const char TAB = '\t';

//efsta lagið

ConsoleUI::ConsoleUI()
{

}

void ConsoleUI::WelcomeMenu()
{

    cout << endl;
    cout << endl;
    cout << TAB << "--------------------------------------------" << endl;
    cout << TAB << " Welcome! This program will store or show" << endl;
    cout << TAB << " famous computer scientists. " << endl;
    cout << TAB << "--------------------------------------------" << endl;
    cout << endl;

}

void ConsoleUI::features()
{
    cout << TAB << "----------------------------------------------------------------------------" << endl;
    cout << TAB << "The list below shows you all possible features on what you can do." << endl;
    cout << endl;
    cout << TAB << "press H to show all options" << endl; //eitthvað svona er sniðgt;
    cout << TAB << "Press 1 to create a new scientist." << endl;
    cout << TAB << "Press 2 to list all scientists." << endl;
    cout << TAB << "Press 3 to search for a scientist." << endl;
    cout << TAB << "Press Q to quit the program." << endl;
    cout << TAB << "----------------------------------------------------------------------------" << endl;
    cout << endl;

   /* vector<Scientist> temp = service.getScientists();
    // testing txt file
    cout << "\t |Name: " << temp[0].getName() << endl;
    cout << "\t |Gender: " << temp[0].getGender() << endl;
    cout << "\t |Born: " << temp[0].getDateOfBirth() << endl;
    cout << "\t |Died: " << temp[0].getDateOfDeath() << endl;
    // no longer testing txt*/
}

void ConsoleUI::readScientists()
{
    Scientist temp;

    //vector<Scientist> scientists = service.getScientists();

    string tempName;
    cout << TAB << "Please enter a name: ";
    cin.ignore(64,'\n');
    getline(cin, tempName);
    do
    {
        if(tempName.empty())
        {

            getline(cin, tempName);
            cout << TAB << "You cannot enter a empty name. Please try again: " << endl;
            getline(cin, tempName);
        }
    }
    while(tempName.empty());

    temp.setName(tempName);

    bool validGender = false;
    string tempGender;

    char gender;
    cout << TAB << "Please enter the gender(M for male, F for female): ";

        while(validGender == false)
        {
            cin >> gender;

            if(gender != 'M' && gender != 'm' && gender != 'F' && gender != 'f')
            {
                cout << TAB << gender << " is not a walid option" << endl;
                cout << TAB <<"pleas enter a vaild option" << endl;

            }
            if(gender == 'M'||gender=='m')
            {
                tempGender = "Male";
                temp.setGender(tempGender);
                validGender = true;
            }
            else if(gender == 'F'||gender == 'f')
            {
                tempGender = "Female";
                temp.setGender(tempGender);
                validGender = true;
            }
        }

        int tempDateOfBirth;
            int tempDateOfDeath;
            cout << TAB << "Please enter date of birth: ";

            do
            {
                cin >> tempDateOfBirth;
                if(tempDateOfBirth > 2016)
                {
                    cout << TAB << "Invalid date. Please try again: " << endl;
                }
                else if(tempDateOfBirth < 0)
                {
                    cout << TAB << "A person cannot have a negative date of birth. Please try again: ";
                }
                else if(!cin)
                {
                    while((!cin))
                    {
                    cin.clear();
                    cin.ignore(numeric_limits<streamsize>::max(),'\n');
                    cout << TAB << "Invalid date,This is not a year, try again" << endl;
                    cout << TAB <<"Please enter date of birth: ";
                    cin >> tempDateOfBirth;
                    }
                }

            }
            while(tempDateOfBirth > 2016 || tempDateOfBirth < 0);

            temp.setDateOfBirth(tempDateOfBirth);
            cout << endl;

            cout << TAB << "Please enter date of death(Enter 0 if the scientist is still alive): ";

            do
           {
                cin >> tempDateOfDeath;
                if(!cin)
                    {
                        while((!cin))
                        {
                        cin.clear();
                        cin.ignore(numeric_limits<streamsize>::max(),'\n');
                        cout << TAB << "Invalid date,This is not a year, try again" << endl;
                        cout << TAB << "Please enter date of death(Enter 13337 if the scientist is still alive): ";
                        cin >> tempDateOfDeath;
                        }
                    }
                else if((tempDateOfDeath < tempDateOfBirth)&&(tempDateOfDeath != 0))
                {
                    cout << TAB << "Not possible. A person cannot die before it is born." << endl;
                    cout << TAB << "Please enter date of death(Enter 0 if the scientist is still alive): ";
                    cin.clear();
                    cin >> tempDateOfDeath;
                }

            }
            while((tempDateOfDeath < tempDateOfBirth)&&(tempDateOfDeath != 0));

                if(tempDateOfDeath > 2016)
                {
                    cout << "Not possible. A person cannot die beyond the current year." << endl;
                }

            //while(tempDateOfDeath < tempDateOfBirth);

            //temp.setDateOfDeath(tempDateOfDeath);

            cout << endl;

            char cont;
            cout << TAB << "Do you want to add another scientist? Press Y/y for yes or N/n for no: ";
            cin >> cont;
            if(cont == 'y' || cont == 'Y')
            {
                readScientists();
            }
            else
            {
                features();
            }

    //scientists.push_back(temp);

    //flytur upplýsingar inn í ScientistService
    service.create(temp);
}

void ConsoleUI::display(vector<Scientist> scientists) // hjálp
{
    cout << "\t information about all listed scientist" << endl;
    cout << "\t___________________________________________________________________________" << endl;
    for(size_t i = 0; i < scientists.size(); i++)
    {
        cout << "\t |Name: " << scientists[i].getName() << endl;
        cout << "\t |Gender: " << scientists[i].getGender() << endl;
        cout << "\t |Born: " << scientists[i].getDateOfBirth() << endl;
        if(scientists[i].getDateOfDeath() == 13337)
            cout << "\t |Still alive " << endl;
        else
            cout << "\t |Died: " << scientists[i].getDateOfDeath() << endl;
        cout << TAB << "----------------------------------------------------------------------------" << endl;
    }
}

void ConsoleUI::displayListOfScientistsAlpha()
{
    vector<Scientist> scientists = service.getScientistsAlpha();
    display(scientists);

 }

void ConsoleUI::displayListOfScientistsYoung()
{
    vector<Scientist> scientists = service.getScientistsYoung();
    display(scientists);
}

void ConsoleUI::displayListOfScientistsOld()
{
    vector<Scientist> scientists = service.getScientistsOld();
    display(scientists);
}

void ConsoleUI::searchName()
{
    string name;
    cout << "Enter name of scientists you want to find: ";
    cin.ignore();
    getline(cin, name);

     vector<Scientist> temp = service.searchName(name);
     if(temp.size() == 0)
     {
         cout << "No scientist name " << name << " in our data, try again" << endl;
     }
     else
     {
         display(temp);
     }

}

void ConsoleUI::searchDateOfBirth()
{

    int year = 0;
    cout << "Enter the the year of birth of the Scientist: ";
    cin >> year;

    vector<Scientist> temp = service.searchDateOfBirth(year);
    if(temp.size() == 0)
    {
        cout << "No scientist in our data born that year, try again" << endl;
    }
    else
    {
        display(temp);
    }
}

void ConsoleUI::searchGender()
{
    //vector<Scientist> temp = service.getScientists();

    char gender;
    cout << "Please enter the gender(M for male, F for female): " << endl;

    cin >> gender;

    vector<Scientist> temp = service.searchGender(gender);
    if(temp.size() == 0)
    {
        if(gender == 'M' || gender == 'm')
        {
            cout << TAB << "There are no male scientist, try again" << endl;
        }
        if(gender == 'F' || gender == 'f')
        {
            cout << TAB<< "There are no male scientist, try again" << endl;
        }
    }
    else
    {
        display(temp);
    }

}

void ConsoleUI::listOrSortScientist()
{
    string choice;

    while(choice != "q" && choice != "Q")
    {
        vector<Scientist> temp = service.getScientists();

        cout << TAB << "Please choose a feature: ";
        cin >> choice;
        cout << endl;

        if(choice == "h" || choice == "H")
        {
            features();
        }

        else if(choice == "1")
        {
            cout << TAB << ">>> Reading Scientists <<<" << endl << endl;
            readScientists();
        }

        else if(choice == "2")
        {
            int sort;
            cout << TAB << "How should the list be sorted?" << endl;
            cout << TAB << "Press 1 for alphabetical order." << endl;
            cout << TAB << "Press 2 to sort from youngest to oldest." << endl;
            cout << TAB << "Press 3 to sort from oldest to youngest." << endl;
            cout << TAB << "Press any other number to go BACK to menu." << endl;
            cout << TAB << "" << endl;
            cout << TAB << "----------------------------------------------------------------------------" << endl;

            cin >> sort;

            if(sort == 1)
            {
                displayListOfScientistsAlpha();
            }
            if(sort == 2)
            {
                displayListOfScientistsYoung();
            }
            if(sort == 3)
            {
                displayListOfScientistsOld();
            }
        }

        else if(choice == "3")
        {
            int searchOptions = 0;

            cout << TAB << "What do you want to search by?" << endl;
            cout << TAB << "Press 1 to search for a scientist witch a specific name" << endl;
            cout << TAB << "Press 2 to search for all scientists born a specific year" << endl;
            cout << TAB << "Press 3 to search for all scientists with a specific gender" << endl;

            cin >> searchOptions;

            if(searchOptions == 1)
            {
                searchName();
            }
            else if(searchOptions == 2)
            {
                searchDateOfBirth();
            }
            else if(searchOptions == 3)
            {
                searchGender();
            }
        }
    }
}

<commit_msg>Finpussadi consoleUI.cpp<commit_after>#include <iostream>
#include <string>
#include <limits>
#include "consoleui.h"

using namespace std;

const char TAB = '\t';

ConsoleUI::ConsoleUI()
{

}

void ConsoleUI::WelcomeMenu()
{

    cout << endl;
    cout << endl;
    cout << TAB << "--------------------------------------------" << endl;
    cout << TAB << " Welcome! This program will store or show" << endl;
    cout << TAB << " famous computer scientists. " << endl;
    cout << TAB << "--------------------------------------------" << endl;
    cout << endl;

}

void ConsoleUI::features()
{
    cout << TAB << "----------------------------------------------------------------------------" << endl;
    cout << TAB << "The list below shows you all possible features on what you can do." << endl;
    cout << endl;
    cout << TAB << "press H to show all options" << endl; //eitthvað svona er sniðgt;
    cout << TAB << "Press 1 to create a new scientist." << endl;
    cout << TAB << "Press 2 to list all scientists." << endl;
    cout << TAB << "Press 3 to search for a scientist." << endl;
    cout << TAB << "Press Q to quit the program." << endl;
    cout << TAB << "----------------------------------------------------------------------------" << endl;
    cout << endl;
}
void ConsoleUI::readScientists()
{
    Scientist temp;

    //vector<Scientist> scientists = service.getScientists();

    string tempName;
    cout << TAB << "Please enter a name: ";
    cin.ignore(64,'\n');
    getline(cin, tempName);
    do
    {
        if(tempName.empty())
        {
            getline(cin, tempName);
            cout << TAB << "You cannot enter a empty name. Please try again: " << endl;
            getline(cin, tempName);
        }
    }
    while(tempName.empty());
    temp.setName(tempName);

    bool validGender = false;
    string tempGender;

    char gender;
    cout << TAB << "Please enter the gender(M for male, F for female): ";

        while(validGender == false)
        {
            cin >> gender;

            if(gender != 'M' && gender != 'm' && gender != 'F' && gender != 'f')
            {
                cout << TAB << gender << " is not a valid option" << endl;
                cout << TAB <<"pleas enter a vaild option" << endl;
            }
            if(gender == 'M'||gender=='m')
            {
                tempGender = "Male";
                temp.setGender(tempGender);
                validGender = true;
            }
            else if(gender == 'F'||gender == 'f')
            {
                tempGender = "Female";
                temp.setGender(tempGender);
                validGender = true;
            }
        }

            int tempDateOfBirth;
            int tempDateOfDeath;
            cout << TAB << "Please enter date of birth: ";

            do
            {
                cin >> tempDateOfBirth;
                if(tempDateOfBirth > 2016)
                {
                    cout << TAB << "Invalid date. Please try again: " << endl;
                }
                else if(tempDateOfBirth < 0)
                {
                    cout << TAB << "A person cannot have a negative date of birth. Please try again: ";
                }
                else if(!cin)
                {
                    while((!cin))
                    {
                    cin.clear();
                    cin.ignore(numeric_limits<streamsize>::max(),'\n');
                    cout << TAB << "That is not a date, please try again: " << endl;
                    cout << TAB << "Please enter date of birth: ";
                    cin >> tempDateOfBirth;
                    }
                }

            }
            while(tempDateOfBirth > 2016 || tempDateOfBirth < 0);

            temp.setDateOfBirth(tempDateOfBirth);

            cout << TAB << "Please enter a date of death(Enter 0 if the scientist is still alive): ";

            do
           {
                cin >> tempDateOfDeath;
                if(!cin)
                    {
                        while((!cin))
                        {
                        cin.clear();
                        cin.ignore(numeric_limits<streamsize>::max(),'\n');
                        cout << TAB << "Invalid date, that is not a year, try again:" << endl;
                        cout << TAB << "Please enter a date of death(Enter 0 if the scientist is still alive): ";
                        cin >> tempDateOfDeath;
                        }
                    }
                else if((tempDateOfDeath < tempDateOfBirth)&&(tempDateOfDeath != 0))
                {
                    cout << TAB << "Not possible. A person cannot die before it is born." << endl;
                    cout << TAB << "Please enter a date of death(Enter 0 if the scientist is still alive): ";
                    cin.clear();
                    cin >> tempDateOfDeath;
                }

            }
            while((tempDateOfDeath < tempDateOfBirth)&&(tempDateOfDeath != 0));

                if(tempDateOfDeath > 2016)
                {
                    cout << TAB << "Not possible. A person cannot die beyond the current year." << endl;
                }

            cout << endl;

            char cont;
            cout << TAB << "Do you want to add another scientist? Press Y/y for yes or N/n for no: ";
            cin >> cont;
            if(cont == 'y' || cont == 'Y')
            {
                readScientists();
            }
            else
            {
                features();
            }

    //flytur upplýsingar inn í ScientistService
    service.create(temp);
}

void ConsoleUI::display(vector<Scientist> scientists)
{
    cout << "\t Information about all listed scientists" << endl;
    cout << "\t___________________________________________________________________________" << endl;
    for(size_t i = 0; i < scientists.size(); i++)
    {
        cout << "\t |Name: " << scientists[i].getName() << endl;
        cout << "\t |Gender: " << scientists[i].getGender() << endl;
        cout << "\t |Born: " << scientists[i].getDateOfBirth() << endl;
        if(scientists[i].getDateOfDeath() == 0)
            cout << "\t |Still alive " << endl;
        else
            cout << "\t |Died: " << scientists[i].getDateOfDeath() << endl;
        cout << TAB << "----------------------------------------------------------------------------" << endl;
    }
}

void ConsoleUI::displayListOfScientistsAlpha()
{
    vector<Scientist> scientists = service.getScientistsAlpha();
    display(scientists);
}

void ConsoleUI::displayListOfScientistsYoung()
{
    vector<Scientist> scientists = service.getScientistsYoung();
    display(scientists);
}

void ConsoleUI::displayListOfScientistsOld()
{
    vector<Scientist> scientists = service.getScientistsOld();
    display(scientists);
}

void ConsoleUI::searchName()
{
     string name;
     cout << TAB << "Enter the name of the scientist you want to find: ";
     cin.ignore();
     getline(cin, name);

     vector<Scientist> temp = service.searchName(name);
     if(temp.size() == 0)
     {
         cout << TAB << "There is no scientist with the name " << name << " in our data, please try again: " << endl;
     }
     else
     {
         display(temp);
     }
}

void ConsoleUI::searchDateOfBirth()
{
    int year = 0;
    cout << TAB << "Enter the scientists year of birth: ";
    cin >> year;

    vector<Scientist> temp = service.searchDateOfBirth(year);
    if(temp.size() == 0)
    {
        cout << TAB << "There is no scientist in our database with that date of birth, please try again:" << endl;
    }
    else
    {
        display(temp);
    }
}

void ConsoleUI::searchGender()
{
    char gender;
    cout << TAB << "Please enter a gender(M for male, F for female): " << endl;

    cin >> gender;

    vector<Scientist> temp = service.searchGender(gender);
    if(temp.size() == 0)
    {
        if(gender == 'M' || gender == 'm')
        {
            cout << TAB << "There are no male scientists, try again:" << endl;
        }
        if(gender == 'F' || gender == 'f')
        {
            cout << TAB << "There are no female scientists, try again:" << endl;
        }
    }
    else
    {
        display(temp);
    }
}

void ConsoleUI::listOrSortScientist()
{
    string choice;

    while(choice != "q" && choice != "Q")
    {
        vector<Scientist> temp = service.getScientists();

        cout << TAB << "Please choose a feature: ";
        cin >> choice;
        cout << endl;

        if(choice == "h" || choice == "H")
        {
            features();
        }

        else if(choice == "1")
        {
            cout << TAB << ">>> Reading Scientists <<<" << endl << endl;
            readScientists();
        }

        else if(choice == "2")
        {
            int sort;
            cout << TAB << "How should the list be sorted?" << endl;
            cout << TAB << "Press 1 for alphabetical order." << endl;
            cout << TAB << "Press 2 to sort from youngest to oldest." << endl;
            cout << TAB << "Press 3 to sort from oldest to youngest." << endl;
            cout << TAB << "Press any other number to go BACK to the menu." << endl;
            cout << TAB << "" << endl;
            cout << TAB << "----------------------------------------------------------------------------" << endl;

            cin >> sort;

            if(sort == 1)
            {
                displayListOfScientistsAlpha();
            }
            if(sort == 2)
            {
                displayListOfScientistsYoung();
            }
            if(sort == 3)
            {
                displayListOfScientistsOld();
            }
        }

        else if(choice == "3")
        {
            int searchOptions = 0;

            cout << TAB << "What do you want to search for?" << endl;
            cout << TAB << "Press 1 to search for a scientist witch a specific name:" << endl;
            cout << TAB << "Press 2 to search for all scientists born in a specific year:" << endl;
            cout << TAB << "Press 3 to search for all scientists with a specific gender:" << endl;

            cout << TAB;
            cin >> searchOptions;

            if(searchOptions == 1)
            {
                searchName();
            }
            else if(searchOptions == 2)
            {
                searchDateOfBirth();
            }
            else if(searchOptions == 3)
            {
                searchGender();
            }
        }
    }
}

<|endoftext|>


<commit_before>#include "GBase.h"
#include "GArgs.h"
#include <ctype.h>

GArgs::GArgs(int argc, char* argv[], const char* format, bool nodigitopts) {
   /* format can be:
      <string>{;|=} e.g. disable-test;PID=S= for --disable-test PID=50 (or --PID 50) S=3.5 etc.
      <letter>[:]  e.g. p:hT  for -p testing (or -ptesting) -h -T
   */
const char* fstr=format;
fmtcount=0;
count=0;
nonOptCount=0;
nonOptPos=0;
optPos=0;
errarg=0;
err_valmissing=false;
args=NULL;
fmt=NULL;
_argc=argc;
_argv=argv;
int fmtlen=strlen(format);
//---- first parse the format string
while (fstr-format < fmtlen ) {
  int l=strcspn(fstr, ";=:");
  if (fstr[l]==0) { //end of string reached
      //all previous chars are just switches:
       GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef));
       //store each switch
       for (int i=0; i<l;i++) {
         fmt[fmtcount+i].longopt=NULL;
         fmt[fmtcount+i].opt=fstr[i];
         fmt[fmtcount+i].req_value = false;
         fmt[fmtcount+i].code=fmtcount+i+1;
         }
       fmtcount+=l;
       break;
     }
   else {
     if (fstr[l]==':') {
         //fstr[l-1] is an argument, but all the previous are just switches
         GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef));
         //store each switch AND the option
         for (int i=0; i<l;i++) {
           fmt[fmtcount+i].longopt=NULL; //one char length
           fmt[fmtcount+i].opt=fstr[i];
           fmt[fmtcount+i].req_value = (i==l-1);
           fmt[fmtcount+i].code=fmtcount+i+1;
           }
         fmtcount+=l;
         }
      else { // fstr[l]=='=' or ';'
         GREALLOC(fmt, (fmtcount+1)*sizeof(fmtdef));
         fmt[fmtcount].longopt=Gstrdup(fstr, fstr+l-1);
         fmt[fmtcount].opt=0;
         fmt[fmtcount].req_value=(fstr[l]=='=');
         fmt[fmtcount].code=fmtcount+1;
         fmtcount++;
         }
     fstr+=l+1;
     }
  }
 //-- now parse the arguments based on the given format specification
 parseArgs(nodigitopts);
 }

void dbg_dequote(char* &p) {
   int alen=strlen(p);
   if (alen>1 && p[0]=='\'' && p[alen-1]=='\'') {
	 p++;
	 p[alen-2 ]='\0';
   }
}

int GArgs::parseArgs(bool nodigitopts) {
  int p=1; //skip program name
  int f=0;
  while (p<_argc) {
   // silly patch for annnoying MacOS gdb/eclipse issues:
   #if defined(__APPLE__) && defined(DEBUG)
	   dbg_dequote(_argv[p]);
   #endif
   //--
   if (_argv[p][0]=='-' && (_argv[p][1]==0 || _argv[p][1]!='-')) {
     //single-dash argument
     int cpos=1;
     char c=_argv[p][cpos];
     if (c==0 || (nodigitopts && isdigit(c)) ||
            (c=='.' && isdigit(_argv[p][cpos+1]))) {
        //special case: plain argument '-' or just a negative number
        GREALLOC(args, (count+1)*sizeof(argdata));
        args[count].opt=NULL;
        args[count].fmti=-1;
        if (c==0) {
          GCALLOC(args[count].value, 2);
          args[count].value[0]='-';
          }
         else { //negative number given
          args[count].value=Gstrdup(_argv[p]);
          }
        count++;
        nonOptCount++;
        }
      else { //single-dash argument or switch
       COLLAPSED:
        if ((f=validShortOpt(c))>=0) {
          GREALLOC(args, (count+1)*sizeof(argdata));
          GCALLOC(args[count].opt, 2);
          args[count].opt[0]=c;
          args[count].fmti=f;
          if (!fmt[f].req_value) {//switch type
            GCALLOC(args[count].value,1);//so getOpt() functions would not return NULL
            count++;
            // only switches can be grouped with some other switches or options
            if (_argv[p][cpos+1]!='\0') {
               cpos++;
               c=_argv[p][cpos];
               goto COLLAPSED;
               }
            }
           else {
              //single-dash argument followed by a value
            if (_argv[p][cpos+1]=='\0') {
                if (p+1<_argc && _argv[p+1][0]!=0) { //value is the whole next argument
                   p++;
				#if defined(__APPLE__) && defined(DEBUG)
				   dbg_dequote(_argv[p]);
				#endif
                   args[count].value=Gstrdup(_argv[p]);
                }
                  else {
                   errarg=p;
                   err_valmissing=true;
                   return errarg;
                   }
                }
               else { //value immediately follows the dash-option
                args[count].value=Gstrdup(_argv[p]+cpos+1);
                }
            count++;
            }
          } //was validShortOpt
         else { //option not found in format definition!
           errarg=p;
           return errarg;
           }
        }
     } //-single-dash
   else {//not a single-dash argument
     char* ap=_argv[p];
     bool is_longopt=false;
     if (*ap=='-' && ap[1]=='-') { //double-dash option
        is_longopt=true;
        ap+=2;
        }
     char* e=strchr(ap+1,'=');
     while (e!=NULL && *(e-1)=='\\') e=strchr(e,'=');
     if (e==NULL && is_longopt) {
        e=ap;
        while (*e!=0 && *e!=' ') e++;
        //e will be on eos or next space
        }
     if (e!=NULL && e>ap) {
       //this must be a long option
       //e is on eos, space or '='
       if ((f=validLongOpt(ap,e-1))>=0) {
            GREALLOC(args, (count+1)*sizeof(argdata));
            args[count].opt=Gstrdup(ap,e-1);
            args[count].fmti=f;
            if (fmt[f].req_value) {
               if (*e==0) {
                   //value is the next argument
                   if (p+1<_argc && _argv[p+1][0]!=0) {
                      p++;
                      args[count].value=Gstrdup(_argv[p]);
                      }
                    else {
                      errarg=p;
                      err_valmissing=true;
                      return errarg;
                      }
                   }
                else { //value is in the same argument
                   //while (*e!=0 && (*e==' ' || *e=='=')) e++;
                   if (*e=='=') e++;
                   if (*e==0) {
                      errarg=p;
                      err_valmissing=true;
                      return errarg;
                      }
                   args[count].value=Gstrdup(e);
                   }
               } //value required
              else { //no value expected
               GCALLOC(args[count].value,1); //do not return NULL
               }
            count++;
            }
          else { //error - this long argument not recognized
           errarg=p;
           return errarg;
           }
        }
      else { //just a plain non-option argument
       if (e==ap) { //i.e. just "--"
          errarg=p;
          return errarg;
          }
       GREALLOC(args, (count+1)*sizeof(argdata));
       args[count].opt=NULL; //it's not an option
       args[count].value=Gstrdup(_argv[p]);
       args[count].fmti=-1;
       count++;
       nonOptCount++;
       }
     }
   p++;//check next arg string
   } //while arguments
 return errarg;
}

void GArgs::printError(FILE* fout, const char* usage, bool exitProgram) {
 if (errarg==0) return;
 if (usage) fprintf(fout, "%s\n", usage);
 if (err_valmissing)
     fprintf(fout, "Error: value required for option '%s'\n", _argv[errarg]);
    else
     fprintf(fout, "Error: invalid argument '%s'\n", _argv[errarg]);
 if (exitProgram)
     exit(1);
}

void GArgs::printError(const char* usage, bool exitProgram) {
 printError(stderr, usage, exitProgram);
}

void GArgs::printCmdLine(FILE* fout) {
 if (_argv==NULL) return;
 for (int i=0;i<_argc;i++) {
   fprintf(fout, "%s%c", _argv[i], (i==_argc-1)?'\n':' ');
   }
}

GArgs::GArgs(int argc, char* argv[], const GArgsDef fmtrecs[], bool nodigitopts) {
 fmtcount=0;
 count=0;
 nonOptCount=0;
 nonOptPos=0;
 optPos=0;
 errarg=0;
 err_valmissing=false;
 args=NULL;
 fmt=NULL;
 _argc=argc;
 _argv=argv;
 if (fmtrecs==NULL) return;

 const GArgsDef* frec=fmtrecs;
 while ((frec->longopt || frec->opt) && fmtcount<255) {
     fmtcount++;
     frec=&(fmtrecs[fmtcount]);
     }
 GCALLOC(fmt, fmtcount*sizeof(fmtdef));
 for (int i=0;i<fmtcount;i++) {
   fmt[i].longopt=Gstrdup(fmtrecs[i].longopt); //do we need to use Gstrdup here?
   fmt[i].opt=fmtrecs[i].opt;
   fmt[i].req_value=fmtrecs[i].req_value;
   fmt[i].code=fmtrecs[i].code;
   }
 parseArgs(nodigitopts);
}

GArgs::~GArgs() {
 int i;
 for (i=0; i<fmtcount; i++)
    GFREE(fmt[i].longopt);
 GFREE(fmt);
 for (i=0; i<count; i++) {
  GFREE(args[i].opt);
  GFREE(args[i].value);
  }
 GFREE(args);
}

int GArgs::validShortOpt(char o) {
 for (int i=0; i<fmtcount; i++)
  if (fmt[i].opt==o) return i;
 return -1;
}

int GArgs::validLongOpt(char* o, char* to) {
 char* pstr=Gstrdup(o,to);
 for (int i=0; i<fmtcount; i++) {
  if (fmt[i].longopt && strcmp(fmt[i].longopt, pstr)==0) {
       GFREE(pstr);
       return i;
       }
  }
 GFREE(pstr);
 return -1;
}

int GArgs::validOpt(int code) {
 for (int i=0; i<fmtcount; i++)
   if (fmt[i].code==code) return i;
 return -1;
}

int GArgs::isError() { // returns the offending argv position or 0 if no error
 return errarg;
 }

char* GArgs::getOpt(const char* o) { /* retrieve the value for option o
                   returns
                       NULL    if option not given at all
                     !=NULL    if boolean option was given
                     opt.value if value option was given
                     */
 for (int i=0; i<count; i++)
  if (args[i].opt!=NULL && strcmp(args[i].opt, o)==0)
           return args[i].value;
 return NULL;
}

char* GArgs::getOpt(const char o) {
 for (int i=0; i<count; i++)
  if (args[i].opt!=NULL && args[i].opt[0]==o && args[i].opt[1]=='\0')
      return args[i].value;
 return NULL;
}

char* GArgs::getOpt(int c) {
 for (int i=0; i<count; i++)
  if (args[i].fmti>=0 && fmt[args[i].fmti].code==c)
      return args[i].value;
 return NULL;
}

char* GArgs::getOptName(int c) {
 for (int i=0; i<count; i++)
  if (args[i].fmti>=0 && fmt[args[i].fmti].code==c)
      return args[i].opt;
 return NULL;
}

int GArgs::startNonOpt(){ //reset iteration through non-option arguments
   //returns the number of non-option arguments
nonOptPos=0;
return nonOptCount;
}

char* GArgs::nextNonOpt() { //get the next non-dashed argument
               //or NULL if no more
for (int i=nonOptPos;i<count;i++)
 if (args[i].opt==NULL) {
      nonOptPos=i+1;
      return args[i].value;
      }
return NULL;
}

int GArgs::startOpt(){ //reset iteration through option arguments
   //returns the number of option arguments
optPos=0;
return count-nonOptCount;
}

char* GArgs::nextOpt() { //get the next non-dashed argument
               //or NULL if no more
for (int i=optPos;i<count;i++)
 if (args[i].opt!=NULL) {
      optPos=i+1;
      return args[i].opt;
      }
return NULL;
}

int GArgs::nextCode() { //get the next non-dashed argument
               //or NULL if no more
for (int i=optPos;i<count;i++)
 if (args[i].opt!=NULL && args[i].fmti>=0) {
      optPos=i+1;
      return fmt[args[i].fmti].code;
      }
return 0; //must make sure that codes are > 0 for this to work properly
}

<commit_msg>fix gargs<commit_after>#include "GBase.h"
#include "GArgs.h"
#include <ctype.h>

GArgs::GArgs(int argc, char* argv[], const char* format, bool nodigitopts) {
   /* format can be:
      <string>{;|=} e.g. disable-test;PID=S= for --disable-test PID=50 (or --PID 50) S=3.5 etc.
      <letter>[:]  e.g. p:hT  for -p testing (or -ptesting) -h -T
   */
const char* fstr=format;
fmtcount=0;
count=0;
nonOptCount=0;
nonOptPos=0;
optPos=0;
errarg=0;
err_valmissing=false;
args=NULL;
fmt=NULL;
_argc=argc;
_argv=argv;
int fmtlen=strlen(format);
//---- first parse the format string
while (fstr-format < fmtlen ) {
  int l=strcspn(fstr, ";=:");
  if (fstr[l]==0) { //end of string reached
      //all previous chars are just switches:
       GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef));
       //store each switch
       for (int i=0; i<l;i++) {
         fmt[fmtcount+i].longopt=NULL;
         fmt[fmtcount+i].opt=fstr[i];
         fmt[fmtcount+i].req_value = false;
         fmt[fmtcount+i].code=fmtcount+i+1;
         }
       fmtcount+=l;
       break;
     }
   else {
     if (fstr[l]==':') {
         //fstr[l-1] is an argument, but all the previous are just switches
         GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef));
         //store each switch AND the option
         for (int i=0; i<l;i++) {
           fmt[fmtcount+i].longopt=NULL; //one char length
           fmt[fmtcount+i].opt=fstr[i];
           fmt[fmtcount+i].req_value = (i==l-1);
           fmt[fmtcount+i].code=fmtcount+i+1;
           }
         fmtcount+=l;
         }
      else { // fstr[l]=='=' or ';'
         GREALLOC(fmt, (fmtcount+1)*sizeof(fmtdef));
         fmt[fmtcount].longopt=Gstrdup(fstr, fstr+l-1);
         fmt[fmtcount].opt=0;
         fmt[fmtcount].req_value=(fstr[l]=='=');
         fmt[fmtcount].code=fmtcount+1;
         fmtcount++;
         }
     fstr+=l+1;
     }
  }
 //-- now parse the arguments based on the given format specification
 parseArgs(nodigitopts);
 }

void dbg_dequote(char* &p) {
   int alen=strlen(p);
   if (alen>1 && p[0]=='\'' && p[alen-1]=='\'') {
	 p++;
	 p[alen-2 ]='\0';
   }
}

int GArgs::parseArgs(bool nodigitopts) {
  int p=1; //skip program name
  int f=0;
  while (p<_argc) {
   // silly patch for annnoying MacOS gdb/eclipse issues:
   #if defined(__APPLE__) && defined(DEBUG)
	   dbg_dequote(_argv[p]);
   #endif
   //--
   if (_argv[p][0]=='-' && (_argv[p][1]==0 || _argv[p][1]!='-')) {
     //single-dash argument
     int cpos=1;
     char c=_argv[p][cpos];
     if (c==0 || (nodigitopts && isdigit(c)) ||
            (c=='.' && isdigit(_argv[p][cpos+1]))) {
        //special case: plain argument '-' or just a negative number
        GREALLOC(args, (count+1)*sizeof(argdata));
        args[count].opt=NULL;
        args[count].fmti=-1;
        if (c==0) {
          GCALLOC(args[count].value, 2);
          args[count].value[0]='-';
          }
         else { //negative number given
          args[count].value=Gstrdup(_argv[p]);
          }
        count++;
        nonOptCount++;
        }
      else { //single-dash argument or switch
       COLLAPSED:
        if ((f=validShortOpt(c))>=0) {
          GREALLOC(args, (count+1)*sizeof(argdata));
          GCALLOC(args[count].opt, 2);
          args[count].opt[0]=c;
          args[count].fmti=f;
          if (!fmt[f].req_value) {//switch type
            GCALLOC(args[count].value,1);//so getOpt() functions would not return NULL
            count++;
            // only switches can be grouped with some other switches or options
            if (_argv[p][cpos+1]!='\0') {
               cpos++;
               c=_argv[p][cpos];
               goto COLLAPSED;
               }
            }
           else {
              //single-dash argument followed by a value
            if (_argv[p][cpos+1]=='\0') {
                if (p+1<_argc && _argv[p+1][0]!=0) { //value is the whole next argument
                   p++;
				#if defined(__APPLE__) && defined(DEBUG)
				   dbg_dequote(_argv[p]);
				#endif
                   args[count].value=Gstrdup(_argv[p]);
                }
                  else {
                   errarg=p;
                   err_valmissing=true;
                   return errarg;
                   }
                }
               else { //value immediately follows the dash-option
                args[count].value=Gstrdup(_argv[p]+cpos+1);
                }
            count++;
            }
          } //was validShortOpt
         else { //option not found in format definition!
           errarg=p;
           return errarg;
           }
        }
     } //-single-dash
   else {//not a single-dash argument
     char* ap=_argv[p];
     bool is_longopt=false;
     if (*ap=='-' && ap[1]=='-') { //double-dash option
        is_longopt=true;
        ap+=2;
        }
     char* e=strchr(ap+1,'=');
     while (e!=NULL && *(e-1)=='\\') e=strchr(e,'=');
     if (e==NULL && is_longopt) {
        e=ap;
        while (*e!=0 && *e!=' ') e++;
        //e will be on eos or next space
        }
     if (e!=NULL && e>ap) {
       //this must be a long option
       //e is on eos, space or '='
       if ((f=validLongOpt(ap,e-1))>=0) {
            GREALLOC(args, (count+1)*sizeof(argdata));
            args[count].opt=Gstrdup(ap,e-1);
            args[count].fmti=f;
            if (fmt[f].req_value) {
               if (*e==0) {
                   //value is the next argument
                   if (p+1<_argc && _argv[p+1][0]!=0) {
                      p++;
					#if defined(__APPLE__) && defined(DEBUG)
                      dbg_dequote(_argv[p]);
   	   	   	   	   	#endif
                      args[count].value=Gstrdup(_argv[p]);
                      }
                    else {
                      errarg=p;
                      err_valmissing=true;
                      return errarg;
                      }
                   }
                else { //value is in the same argument
                   //while (*e!=0 && (*e==' ' || *e=='=')) e++;
                   if (*e=='=') e++;
                   if (*e==0) {
                      errarg=p;
                      err_valmissing=true;
                      return errarg;
                      }
                   args[count].value=Gstrdup(e);
                   }
               } //value required
              else { //no value expected
               GCALLOC(args[count].value,1); //do not return NULL
               }
            count++;
            }
          else { //error - this long argument not recognized
           errarg=p;
           return errarg;
           }
        }
      else { //just a plain non-option argument
       if (e==ap) { //i.e. just "--"
          errarg=p;
          return errarg;
          }
       GREALLOC(args, (count+1)*sizeof(argdata));
       args[count].opt=NULL; //it's not an option
       args[count].value=Gstrdup(_argv[p]);
       args[count].fmti=-1;
       count++;
       nonOptCount++;
       }
     }
   p++;//check next arg string
   } //while arguments
 return errarg;
}

void GArgs::printError(FILE* fout, const char* usage, bool exitProgram) {
 if (errarg==0) return;
 if (usage) fprintf(fout, "%s\n", usage);
 if (err_valmissing)
     fprintf(fout, "Error: value required for option '%s'\n", _argv[errarg]);
    else
     fprintf(fout, "Error: invalid argument '%s'\n", _argv[errarg]);
 if (exitProgram)
     exit(1);
}

void GArgs::printError(const char* usage, bool exitProgram) {
 printError(stderr, usage, exitProgram);
}

void GArgs::printCmdLine(FILE* fout) {
 if (_argv==NULL) return;
 for (int i=0;i<_argc;i++) {
   fprintf(fout, "%s%c", _argv[i], (i==_argc-1)?'\n':' ');
   }
}

GArgs::GArgs(int argc, char* argv[], const GArgsDef fmtrecs[], bool nodigitopts) {
 fmtcount=0;
 count=0;
 nonOptCount=0;
 nonOptPos=0;
 optPos=0;
 errarg=0;
 err_valmissing=false;
 args=NULL;
 fmt=NULL;
 _argc=argc;
 _argv=argv;
 if (fmtrecs==NULL) return;

 const GArgsDef* frec=fmtrecs;
 while ((frec->longopt || frec->opt) && fmtcount<255) {
     fmtcount++;
     frec=&(fmtrecs[fmtcount]);
     }
 GCALLOC(fmt, fmtcount*sizeof(fmtdef));
 for (int i=0;i<fmtcount;i++) {
   fmt[i].longopt=Gstrdup(fmtrecs[i].longopt); //do we need to use Gstrdup here?
   fmt[i].opt=fmtrecs[i].opt;
   fmt[i].req_value=fmtrecs[i].req_value;
   fmt[i].code=fmtrecs[i].code;
   }
 parseArgs(nodigitopts);
}

GArgs::~GArgs() {
 int i;
 for (i=0; i<fmtcount; i++)
    GFREE(fmt[i].longopt);
 GFREE(fmt);
 for (i=0; i<count; i++) {
  GFREE(args[i].opt);
  GFREE(args[i].value);
  }
 GFREE(args);
}

int GArgs::validShortOpt(char o) {
 for (int i=0; i<fmtcount; i++)
  if (fmt[i].opt==o) return i;
 return -1;
}

int GArgs::validLongOpt(char* o, char* to) {
 char* pstr=Gstrdup(o,to);
 for (int i=0; i<fmtcount; i++) {
  if (fmt[i].longopt && strcmp(fmt[i].longopt, pstr)==0) {
       GFREE(pstr);
       return i;
       }
  }
 GFREE(pstr);
 return -1;
}

int GArgs::validOpt(int code) {
 for (int i=0; i<fmtcount; i++)
   if (fmt[i].code==code) return i;
 return -1;
}

int GArgs::isError() { // returns the offending argv position or 0 if no error
 return errarg;
 }

char* GArgs::getOpt(const char* o) { /* retrieve the value for option o
                   returns
                       NULL    if option not given at all
                     !=NULL    if boolean option was given
                     opt.value if value option was given
                     */
 for (int i=0; i<count; i++)
  if (args[i].opt!=NULL && strcmp(args[i].opt, o)==0)
           return args[i].value;
 return NULL;
}

char* GArgs::getOpt(const char o) {
 for (int i=0; i<count; i++)
  if (args[i].opt!=NULL && args[i].opt[0]==o && args[i].opt[1]=='\0')
      return args[i].value;
 return NULL;
}

char* GArgs::getOpt(int c) {
 for (int i=0; i<count; i++)
  if (args[i].fmti>=0 && fmt[args[i].fmti].code==c)
      return args[i].value;
 return NULL;
}

char* GArgs::getOptName(int c) {
 for (int i=0; i<count; i++)
  if (args[i].fmti>=0 && fmt[args[i].fmti].code==c)
      return args[i].opt;
 return NULL;
}

int GArgs::startNonOpt(){ //reset iteration through non-option arguments
   //returns the number of non-option arguments
nonOptPos=0;
return nonOptCount;
}

char* GArgs::nextNonOpt() { //get the next non-dashed argument
               //or NULL if no more
for (int i=nonOptPos;i<count;i++)
 if (args[i].opt==NULL) {
      nonOptPos=i+1;
      return args[i].value;
      }
return NULL;
}

int GArgs::startOpt(){ //reset iteration through option arguments
   //returns the number of option arguments
optPos=0;
return count-nonOptCount;
}

char* GArgs::nextOpt() { //get the next non-dashed argument
               //or NULL if no more
for (int i=optPos;i<count;i++)
 if (args[i].opt!=NULL) {
      optPos=i+1;
      return args[i].opt;
      }
return NULL;
}

int GArgs::nextCode() { //get the next non-dashed argument
               //or NULL if no more
for (int i=optPos;i<count;i++)
 if (args[i].opt!=NULL && args[i].fmti>=0) {
      optPos=i+1;
      return fmt[args[i].fmti].code;
      }
return 0; //must make sure that codes are > 0 for this to work properly
}

<|endoftext|>


<commit_before>#include "packet.h"
#include "main.h"
#include "states.h"

const volatile bool SPI2_LOOPBACK = false;
const volatile bool DMA_TRIGGER_LOOPBACK = false; // pin 17 to 18

IntervalTimer timer;
volatile uint16_t state = SETUP_STATE;
elapsedMicros micro = 0;
volatile unsigned int timeAlive = 0;
volatile int errors = 0;
volatile int bugs = 0;
volatile unsigned int lastLoopTime = 0;
volatile unsigned int lastLoopState = state;
volatile unsigned int lastAnalogRead = 0;
volatile unsigned int numIdles = 0; // Mostly just to count % of loops that we need to clear dma buffer

void setup() {
  Serial.begin(115200);
  delay(500);
  debugPrintf("Serial is on\n");
  timer.begin(heartbeat, 3000000); // Every 3 seconds
  debugPrintf("Set up heartbeat interrupt\n");
  analogReadResolution(16);
  debugPrintf("Begin Spi2\n");
  SPI2.begin();
  debugPrintf("Setting up packet:\n");
  packet_setup();
  debugPrintf("Setting up imu state:\n");
  debugPrintf("Done.\n");
  pinMode(17, OUTPUT); // DMA loopback test
  digitalWriteFast(17, HIGH);
  debugPrintf("Setting up dma:\n");
  dmaSetup();
  debugPrintf("Done!\n");
  debugPrintf("Setting up tracking:\n");
  trackingSetup();
  debugPrintf("Done!\n");
  state = IDLE_STATE;
  delay(1000);
  debugPrintf("Running tests:\n");
  runTests();
  //debugPrintf("Hey %d\n", assert(state != IDLE_STATE));
}

bool assertionError(const char* file, int line, const char* assertion) {
    errors++;
    bugs++;
    Serial.printf("%s, %d: assertion 'assertion' failed, total errors %d, bugs %d\n", file, line, errors, bugs);
    return false;
}

void heartbeat() {
    debugPrintf("State %d,", state);
    debugPrintf("transmitting %d, packetsReceived %d, ", transmitting, packetsReceived);
    debugPrintf("%d errors, bugs %d, last loop %d micros", errors, bugs, lastLoopTime);
    debugPrintf(", last state %d, last read %d, dma offset %d", lastLoopState, lastAnalogRead, dmaGetOffset());
    debugPrintf(", %d loops, time alive %d\n", numIdles, timeAlive);
    if (state == TRACKING_STATE) {
        trackingHeartbeat();
    } else if (state == CALIBRATION_STATE) {
        calibrationHeartbeat();
    }
}

void taskIdle(void) {
    uint16_t rando = random(60000);
    uint16_t receivedTransfer = SPI2.transfer16(rando);
    assert(!SPI2_LOOPBACK || receivedTransfer == rando);
    lastAnalogRead = analogRead(14);
    if (DMA_TRIGGER_LOOPBACK) {
        assert(!dmaSampleReady());
        for (int i = 0; i < DMA_SAMPLE_NUMAXES; i++) {
            digitalWriteFast(17, LOW);
            delayMicroseconds(100);
            digitalWriteFast(17, HIGH);
            delayMicroseconds(1000);
        }
        assert(dmaSampleReady());
        dmaGetSample();
        assert(!dmaSampleReady());
    }
    volatile int garbage = 0;
    for (int i = 0; i < 50000; i++) { // Do some work
        garbage += i;
    }
    numIdles++;
}

void checkTasks(void) {
    long startOfLoop = micro;
    assert(state <= MAX_STATE);
    if (state == IDLE_STATE) {
        taskIdle();
    } else if (state == TRACKING_STATE) {
        taskTracking();
    } else if (state == CALIBRATION_STATE) {
        taskCalibration();
    }

    // Save this into a long because elapsedMillis is not guaranteed in interrupts
    timeAlive = micro / 1000000;
    lastLoopTime = micro - startOfLoop;
    lastLoopState = state;
    // For now just assert, there isn't really a way to recover from a long main loop
    assert(lastLoopTime <= 1000000.0);
}

void loop() {
    checkTasks();
}
<commit_msg>Show weird memcpy behavior<commit_after>#include "packet.h"
#include "main.h"
#include "states.h"

const volatile bool SPI2_LOOPBACK = false;
const volatile bool DMA_TRIGGER_LOOPBACK = false; // pin 17 to 18

IntervalTimer timer;
volatile uint16_t state = SETUP_STATE;
elapsedMicros micro = 0;
volatile unsigned int timeAlive = 0;
volatile int errors = 0;
volatile int bugs = 0;
volatile unsigned int lastLoopTime = 0;
volatile unsigned int lastLoopState = state;
volatile unsigned int lastAnalogRead = 0;
volatile unsigned int numIdles = 0; // Mostly just to count % of loops that we need to clear dma buffer

void setup() {
  Serial.begin(115200);
  delay(500);
  debugPrintf("Serial is on\n");
  timer.begin(heartbeat, 3000000); // Every 3 seconds
  debugPrintf("Set up heartbeat interrupt\n");
  analogReadResolution(16);
  debugPrintf("Begin Spi2\n");
  SPI2.begin();
  debugPrintf("Setting up packet:\n");
  packet_setup();
  debugPrintf("Setting up imu state:\n");
  debugPrintf("Done.\n");
  pinMode(17, OUTPUT); // DMA loopback test
  digitalWriteFast(17, HIGH);
  debugPrintf("Setting up dma:\n");
  dmaSetup();
  debugPrintf("Done!\n");
  debugPrintf("Setting up tracking:\n");
  trackingSetup();
  debugPrintf("Done!\n");
  state = IDLE_STATE;
  debugPrintf("About to do a dank memcpy\n");
  int buf[2] = {1234, 4321};
  memcpy((void *) 0x1ffffffe, buf, 2);
  memcpy((void *) 0x20000000, buf, 2);
  debugPrintf("Done1\n");
  memcpy((void *) 0x1fffffff, buf, 2);
  debugPrintf("Done\n");
  delay(1000);
  debugPrintf("Running tests:\n");
  runTests();
  //debugPrintf("Hey %d\n", assert(state != IDLE_STATE));
}

bool assertionError(const char* file, int line, const char* assertion) {
    errors++;
    bugs++;
    Serial.printf("%s, %d: assertion 'assertion' failed, total errors %d, bugs %d\n", file, line, errors, bugs);
    return false;
}

void heartbeat() {
    debugPrintf("State %d,", state);
    debugPrintf("transmitting %d, packetsReceived %d, ", transmitting, packetsReceived);
    debugPrintf("%d errors, bugs %d, last loop %d micros", errors, bugs, lastLoopTime);
    debugPrintf(", last state %d, last read %d, dma offset %d", lastLoopState, lastAnalogRead, dmaGetOffset());
    debugPrintf(", %d loops, time alive %d\n", numIdles, timeAlive);
    if (state == TRACKING_STATE) {
        trackingHeartbeat();
    } else if (state == CALIBRATION_STATE) {
        calibrationHeartbeat();
    }
}

void taskIdle(void) {
    uint16_t rando = random(60000);
    uint16_t receivedTransfer = SPI2.transfer16(rando);
    assert(!SPI2_LOOPBACK || receivedTransfer == rando);
    lastAnalogRead = analogRead(14);
    if (DMA_TRIGGER_LOOPBACK) {
        assert(!dmaSampleReady());
        for (int i = 0; i < DMA_SAMPLE_NUMAXES; i++) {
            digitalWriteFast(17, LOW);
            delayMicroseconds(100);
            digitalWriteFast(17, HIGH);
            delayMicroseconds(1000);
        }
        assert(dmaSampleReady());
        dmaGetSample();
        assert(!dmaSampleReady());
    }
    volatile int garbage = 0;
    for (int i = 0; i < 50000; i++) { // Do some work
        garbage += i;
    }
    numIdles++;
}

void checkTasks(void) {
    long startOfLoop = micro;
    assert(state <= MAX_STATE);
    if (state == IDLE_STATE) {
        taskIdle();
    } else if (state == TRACKING_STATE) {
        taskTracking();
    } else if (state == CALIBRATION_STATE) {
        taskCalibration();
    }

    // Save this into a long because elapsedMillis is not guaranteed in interrupts
    timeAlive = micro / 1000000;
    lastLoopTime = micro - startOfLoop;
    lastLoopState = state;
    // For now just assert, there isn't really a way to recover from a long main loop
    assert(lastLoopTime <= 1000000.0);
}

void loop() {
    checkTasks();
}
<|endoftext|>


<commit_before>#include "LogConfigReader.hpp"
#include "LogManager.hpp"
#include <yaml-cpp/yaml.h>
#include <fmt/format.h>

static const std::string CONFIG_FILE_NAME = "log-config.yml";

bool ParseLogLevel(YAML::Node const &level_node, LogLevel &dest, std::string const &error_msg)
{
	static const std::unordered_map<std::string, LogLevel> loglevel_str_map = {
		{ "Debug",   LogLevel::DEBUG },
		{ "Info",    LogLevel::INFO },
		{ "Warning", LogLevel::WARNING },
		{ "Error",   LogLevel::ERROR },
		{ "Fatal",   LogLevel::FATAL },
		{ "Verbose", LogLevel::VERBOSE },
		{ "All",     LogLevel::ALL }
	};

	auto const &level_str = level_node.as<std::string>(std::string());
	if (level_str.empty())
	{
		LogManager::Get()->LogInternal(LogLevel::WARNING,
			fmt::format("{}: invalid log level specified", error_msg));
		return false;
	}

	auto const &it = loglevel_str_map.find(level_str);
	if (it == loglevel_str_map.end())
	{
		LogManager::Get()->LogInternal(LogLevel::WARNING,
			fmt::format("{}: invalid log level '{}'", error_msg, level_str));
		return false;
	}

	dest |= (*it).second;
	return true;
}

bool ParseDuration(std::string const &duration, std::chrono::minutes &dest)
{
	auto type_idx = duration.find_first_not_of("0123456789");
	if (type_idx == std::string::npos || type_idx == 0)
		return false;

	int dur = std::stoi(duration); // works as long as the string starts with a number
	switch (tolower(duration.at(type_idx)))
	{
	case 'm':
		dest = std::chrono::minutes(dur);
		break;
	case 'h':
		dest = std::chrono::hours(dur);
		break;
	case 'd':
		dest = std::chrono::hours(dur * 24);
		break;
	case 'w':
		dest = std::chrono::hours(dur * 24 * 7);
		break;
	default:
		return false;
	}

	return true;
}

bool ParseFileSize(std::string const &size, unsigned int &dest_in_kb)
{
	auto type_idx = size.find_first_not_of("0123456789");
	if (type_idx == std::string::npos || type_idx == 0)
		return false;

	int size_val = std::stoi(size); // works as long as the string starts with a number
	if (size.length() != (type_idx + 2) || tolower(size.at(type_idx + 1)) != 'b')
		return false;

	switch (tolower(size.at(type_idx)))
	{
	case 'k':
		dest_in_kb = size_val;
		break;
	case 'm':
		dest_in_kb = size_val * 1000;
		break;
	case 'g':
		dest_in_kb = size_val * 1000 * 1000;
		break;
	default:
		return false;
	}

	return true;
}

LogConfig GetInternalLogConfig()
{
	LogConfig config;
	config.Level = LogLevel::ALL;
	config.PrintToConsole = true;
	return config;
}

void LogConfigReader::ParseConfigFile()
{
	YAML::Node root;
	try
	{
		root = YAML::LoadFile(CONFIG_FILE_NAME);
	}
	catch (const YAML::ParserException& e)
	{
		LogManager::Get()->LogInternal(LogLevel::ERROR,
			fmt::format("could not parse log config file: {}", e.what()));
		return;
	}
	catch (const YAML::BadFile&)
	{
		// file likely doesn't exist, ignore
		return;
	}

	_logger_configs.clear();

	// default settings for log-core logger
	_logger_configs.emplace("log-core", GetInternalLogConfig());

	YAML::Node const &loggers = root["Logger"];
	for (YAML::const_iterator y_it = loggers.begin(); y_it != loggers.end(); ++y_it)
	{
		auto module_name = y_it->first.as<std::string>(std::string());
		if (module_name.empty() || module_name == "log-core")
		{
			LogManager::Get()->LogInternal(LogLevel::ERROR,
				fmt::format("could not parse logger config: invalid logger name"));
			continue;
		}
		LogConfig config;

		std::string const error_msg_loglevel = fmt::format(
			"could not parse log level setting for logger '{}'", module_name);
		YAML::Node const &log_levels = y_it->second["LogLevel"];
		if (log_levels && !log_levels.IsNull()) // log level is specified, remove default log level
			config.Level = LogLevel::NONE;

		if (log_levels.IsSequence())
		{
			for (YAML::const_iterator y_it_level = log_levels.begin();
				y_it_level != log_levels.end(); ++y_it_level)
			{
				ParseLogLevel(*y_it_level, config.Level, error_msg_loglevel);
			}
		}
		else
		{
			ParseLogLevel(log_levels, config.Level, error_msg_loglevel);
		}

		YAML::Node const &log_rotation = y_it->second["LogRotation"];
		if (log_rotation)
		{
			YAML::Node const
				&type = log_rotation["Type"],
				&trigger = log_rotation["Trigger"];
			if (type && trigger)
			{
				static const std::unordered_map<std::string, LogConfig::LogRotationType>
					logrotation_type_str_map = {
					{ "Date", LogConfig::LogRotationType::DATE },
					{ "Size", LogConfig::LogRotationType::SIZE }
				};
				auto const &type_str = type.as<std::string>();
				auto const &it = logrotation_type_str_map.find(type_str);
				if (it != logrotation_type_str_map.end())
				{
					config.Rotation = it->second;
					switch (config.Rotation)
					{
						case LogConfig::LogRotationType::DATE:
						{
							auto time_str = trigger.as<std::string>("24h");
							if (!ParseDuration(time_str, config.LogRotationValue.Date))
							{
								config.LogRotationValue.Date = std::chrono::hours(24);
								LogManager::Get()->LogInternal(LogLevel::WARNING,
									fmt::format(
										"could not parse date log rotation duration " \
										"for logger '{}': invalid duration \"{}\"",
										module_name, time_str));
							}
						} break;
						case LogConfig::LogRotationType::SIZE:
						{
							auto size_str = trigger.as<std::string>("100MB");
							if (!ParseFileSize(size_str, config.LogRotationValue.FileSize))
							{
								config.LogRotationValue.FileSize = 100;
								LogManager::Get()->LogInternal(LogLevel::WARNING,
									fmt::format(
										"could not parse file log rotation size " \
										"for logger '{}': invalid size \"{}\"",
										module_name, size_str));
							}
						} break;
					}
				}
				else
				{
					LogManager::Get()->LogInternal(LogLevel::WARNING,
						fmt::format(
							"could not parse log rotation setting for logger '{}': " \
							"invalid log rotation type '{}'",
							module_name, type_str));
				}
			}
			else
			{
				LogManager::Get()->LogInternal(LogLevel::WARNING,
					fmt::format(
						"could not parse log rotation setting for logger '{}': " \
						"log rotation not completely specified",
						module_name));
			}
		}

		YAML::Node const &console_print = y_it->second["PrintToConsole"];
		if (console_print && console_print.IsScalar())
			config.PrintToConsole = console_print.as<bool>(config.PrintToConsole);

		_logger_configs.emplace(module_name, std::move(config));
	}

	_level_configs.clear();
	YAML::Node const &levels = root["LogLevel"];
	for (YAML::const_iterator y_it = levels.begin(); y_it != levels.end(); ++y_it)
	{
		LogLevel level;
		if (!ParseLogLevel(y_it->first, level, "could not parse log level setting"))
			continue;

		LogLevelConfig config;
		YAML::Node const &console_print_opt = y_it->second["PrintToConsole"];
		if (console_print_opt && console_print_opt.IsScalar())
			config.PrintToConsole = console_print_opt.as<bool>(config.PrintToConsole);

		_level_configs.emplace(level, std::move(config));
	}

	//global config settings
	_globalConfig = GlobalConfig();
	YAML::Node const &enable_colors = root["EnableColors"];
	if (enable_colors && enable_colors.IsScalar())
		_globalConfig.EnableColors = enable_colors.as<bool>(_globalConfig.EnableColors);
}

void LogConfigReader::Initialize()
{
	ParseConfigFile();
	_fileWatcher.reset(new FileChangeDetector(CONFIG_FILE_NAME, [this]()
	{
		LogManager::Get()->LogInternal(LogLevel::INFO,
			"config file change detected, reloading...");
		ParseConfigFile();
		LogManager::Get()->LogInternal(LogLevel::INFO,
			"reloading finished");
	}));
}
<commit_msg>fix log level parsing into uninitialized var<commit_after>#include "LogConfigReader.hpp"
#include "LogManager.hpp"
#include <yaml-cpp/yaml.h>
#include <fmt/format.h>

static const std::string CONFIG_FILE_NAME = "log-config.yml";

bool ParseLogLevel(YAML::Node const &level_node, LogLevel &dest, std::string const &error_msg)
{
	static const std::unordered_map<std::string, LogLevel> loglevel_str_map = {
		{ "Debug",   LogLevel::DEBUG },
		{ "Info",    LogLevel::INFO },
		{ "Warning", LogLevel::WARNING },
		{ "Error",   LogLevel::ERROR },
		{ "Fatal",   LogLevel::FATAL },
		{ "Verbose", LogLevel::VERBOSE },
		{ "All",     LogLevel::ALL }
	};

	auto const &level_str = level_node.as<std::string>(std::string());
	if (level_str.empty())
	{
		LogManager::Get()->LogInternal(LogLevel::WARNING,
			fmt::format("{}: invalid log level specified", error_msg));
		return false;
	}

	auto const &it = loglevel_str_map.find(level_str);
	if (it == loglevel_str_map.end())
	{
		LogManager::Get()->LogInternal(LogLevel::WARNING,
			fmt::format("{}: invalid log level '{}'", error_msg, level_str));
		return false;
	}

	dest |= (*it).second;
	return true;
}

bool ParseDuration(std::string const &duration, std::chrono::minutes &dest)
{
	auto type_idx = duration.find_first_not_of("0123456789");
	if (type_idx == std::string::npos || type_idx == 0)
		return false;

	int dur = std::stoi(duration); // works as long as the string starts with a number
	switch (tolower(duration.at(type_idx)))
	{
	case 'm':
		dest = std::chrono::minutes(dur);
		break;
	case 'h':
		dest = std::chrono::hours(dur);
		break;
	case 'd':
		dest = std::chrono::hours(dur * 24);
		break;
	case 'w':
		dest = std::chrono::hours(dur * 24 * 7);
		break;
	default:
		return false;
	}

	return true;
}

bool ParseFileSize(std::string const &size, unsigned int &dest_in_kb)
{
	auto type_idx = size.find_first_not_of("0123456789");
	if (type_idx == std::string::npos || type_idx == 0)
		return false;

	int size_val = std::stoi(size); // works as long as the string starts with a number
	if (size.length() != (type_idx + 2) || tolower(size.at(type_idx + 1)) != 'b')
		return false;

	switch (tolower(size.at(type_idx)))
	{
	case 'k':
		dest_in_kb = size_val;
		break;
	case 'm':
		dest_in_kb = size_val * 1000;
		break;
	case 'g':
		dest_in_kb = size_val * 1000 * 1000;
		break;
	default:
		return false;
	}

	return true;
}

LogConfig GetInternalLogConfig()
{
	LogConfig config;
	config.Level = LogLevel::ALL;
	config.PrintToConsole = true;
	return config;
}

void LogConfigReader::ParseConfigFile()
{
	YAML::Node root;
	try
	{
		root = YAML::LoadFile(CONFIG_FILE_NAME);
	}
	catch (const YAML::ParserException& e)
	{
		LogManager::Get()->LogInternal(LogLevel::ERROR,
			fmt::format("could not parse log config file: {}", e.what()));
		return;
	}
	catch (const YAML::BadFile&)
	{
		// file likely doesn't exist, ignore
		return;
	}

	_logger_configs.clear();

	// default settings for log-core logger
	_logger_configs.emplace("log-core", GetInternalLogConfig());

	YAML::Node const &loggers = root["Logger"];
	for (YAML::const_iterator y_it = loggers.begin(); y_it != loggers.end(); ++y_it)
	{
		auto module_name = y_it->first.as<std::string>(std::string());
		if (module_name.empty() || module_name == "log-core")
		{
			LogManager::Get()->LogInternal(LogLevel::ERROR,
				fmt::format("could not parse logger config: invalid logger name"));
			continue;
		}
		LogConfig config;

		std::string const error_msg_loglevel = fmt::format(
			"could not parse log level setting for logger '{}'", module_name);
		YAML::Node const &log_levels = y_it->second["LogLevel"];
		if (log_levels && !log_levels.IsNull()) // log level is specified, remove default log level
			config.Level = LogLevel::NONE;

		if (log_levels.IsSequence())
		{
			for (YAML::const_iterator y_it_level = log_levels.begin();
				y_it_level != log_levels.end(); ++y_it_level)
			{
				ParseLogLevel(*y_it_level, config.Level, error_msg_loglevel);
			}
		}
		else
		{
			ParseLogLevel(log_levels, config.Level, error_msg_loglevel);
		}

		YAML::Node const &log_rotation = y_it->second["LogRotation"];
		if (log_rotation)
		{
			YAML::Node const
				&type = log_rotation["Type"],
				&trigger = log_rotation["Trigger"];
			if (type && trigger)
			{
				static const std::unordered_map<std::string, LogConfig::LogRotationType>
					logrotation_type_str_map = {
					{ "Date", LogConfig::LogRotationType::DATE },
					{ "Size", LogConfig::LogRotationType::SIZE }
				};
				auto const &type_str = type.as<std::string>();
				auto const &it = logrotation_type_str_map.find(type_str);
				if (it != logrotation_type_str_map.end())
				{
					config.Rotation = it->second;
					switch (config.Rotation)
					{
						case LogConfig::LogRotationType::DATE:
						{
							auto time_str = trigger.as<std::string>("24h");
							if (!ParseDuration(time_str, config.LogRotationValue.Date))
							{
								config.LogRotationValue.Date = std::chrono::hours(24);
								LogManager::Get()->LogInternal(LogLevel::WARNING,
									fmt::format(
										"could not parse date log rotation duration " \
										"for logger '{}': invalid duration \"{}\"",
										module_name, time_str));
							}
						} break;
						case LogConfig::LogRotationType::SIZE:
						{
							auto size_str = trigger.as<std::string>("100MB");
							if (!ParseFileSize(size_str, config.LogRotationValue.FileSize))
							{
								config.LogRotationValue.FileSize = 100;
								LogManager::Get()->LogInternal(LogLevel::WARNING,
									fmt::format(
										"could not parse file log rotation size " \
										"for logger '{}': invalid size \"{}\"",
										module_name, size_str));
							}
						} break;
					}
				}
				else
				{
					LogManager::Get()->LogInternal(LogLevel::WARNING,
						fmt::format(
							"could not parse log rotation setting for logger '{}': " \
							"invalid log rotation type '{}'",
							module_name, type_str));
				}
			}
			else
			{
				LogManager::Get()->LogInternal(LogLevel::WARNING,
					fmt::format(
						"could not parse log rotation setting for logger '{}': " \
						"log rotation not completely specified",
						module_name));
			}
		}

		YAML::Node const &console_print = y_it->second["PrintToConsole"];
		if (console_print && console_print.IsScalar())
			config.PrintToConsole = console_print.as<bool>(config.PrintToConsole);

		_logger_configs.emplace(module_name, std::move(config));
	}

	_level_configs.clear();
	YAML::Node const &levels = root["LogLevel"];
	for (YAML::const_iterator y_it = levels.begin(); y_it != levels.end(); ++y_it)
	{
		LogLevel level = static_cast<LogLevel>(0); // initialize to zero as ParseLogLevel OR's levels
		if (!ParseLogLevel(y_it->first, level, "could not parse log level setting"))
			continue;

		LogLevelConfig config;
		YAML::Node const &console_print_opt = y_it->second["PrintToConsole"];
		if (console_print_opt && console_print_opt.IsScalar())
			config.PrintToConsole = console_print_opt.as<bool>(config.PrintToConsole);

		_level_configs.emplace(level, std::move(config));
	}

	//global config settings
	_globalConfig = GlobalConfig();
	YAML::Node const &enable_colors = root["EnableColors"];
	if (enable_colors && enable_colors.IsScalar())
		_globalConfig.EnableColors = enable_colors.as<bool>(_globalConfig.EnableColors);
}

void LogConfigReader::Initialize()
{
	ParseConfigFile();
	_fileWatcher.reset(new FileChangeDetector(CONFIG_FILE_NAME, [this]()
	{
		LogManager::Get()->LogInternal(LogLevel::INFO,
			"config file change detected, reloading...");
		ParseConfigFile();
		LogManager::Get()->LogInternal(LogLevel::INFO,
			"reloading finished");
	}));
}
<|endoftext|>


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

#include "boost/python.hpp"

#include "maya/MFnDependencyNode.h"

#include "IECore/Object.h"
#include "IECore/Parameterised.h"
#include "IECore/bindings/PointerFromSWIG.h"

#include "IECoreMaya/bindings/FnParameterisedHolderBinding.h"
#include "IECoreMaya/StatusException.h"
#include "IECoreMaya/ParameterisedHolder.h"

using namespace IECore;
using namespace IECoreMaya;
using namespace boost::python;

static ParameterisedHolderInterface *interface( MFnDependencyNode *fnDN )
{
	MPxNode *userNode = fnDN->userNode();
	if( userNode )
	{
		ParameterisedHolderInterface *interface = dynamic_cast<ParameterisedHolderInterface *>( userNode );
		if( interface )
		{
			return interface;
		}
	}
	// failed
	throw Exception( "Not a ParameterisedHolder" );
}

static void setParameterised( MFnDependencyNode *fnDN, ParameterisedPtr p )
{
	StatusException::throwIfError( interface(fnDN)->setParameterised( p ) );
}

static void setParameterised2( MFnDependencyNode *fnDN, const std::string &className, int classVersion, const std::string &envVarName )
{
	StatusException::throwIfError( interface(fnDN)->setParameterised( className, classVersion, envVarName ) );
}

static boost::python::tuple getParameterised( MFnDependencyNode *fnDN )
{
	std::string className; int classVersion = 0; std::string searchPath;
	ParameterisedPtr p = interface( fnDN )->getParameterised( &className, &classVersion, &searchPath );
	return boost::python::make_tuple( p, className, classVersion, searchPath );
}

static void setNodeValues( MFnDependencyNode *fnDN )
{
	StatusException::throwIfError( interface( fnDN )->setNodeValues() );
}

static void setNodeValue( MFnDependencyNode *fnDN, ParameterPtr pa )
{
	StatusException::throwIfError( interface( fnDN )->setNodeValue( pa ) );
}

static void setParameterisedValues( MFnDependencyNode *fnDN )
{
	StatusException::throwIfError( interface( fnDN )->setParameterisedValues() );
}

static void setParameterisedValue( MFnDependencyNode *fnDN, ParameterPtr pa )
{
	StatusException::throwIfError( interface( fnDN )->setParameterisedValue( pa ) );
}

static std::string parameterPlug( MFnDependencyNode *fnDN, ParameterPtr pa )
{
	// we don't know how to push a swig wrapped MPlug into python,
	// so we have to push the name and then let the python half of
	// MFnParameterisedHolder construct an MPlug from it.
	MString name = interface( fnDN )->parameterPlug( pa ).name();
	return name.asChar();
}

static ParameterPtr plugParameter( MFnDependencyNode *fnDN, MPlug *plug )
{
	return interface( fnDN )->plugParameter( *plug );
}

void IECoreMaya::bindFnParameterisedHolder()
{

	def( "_parameterisedHolderSetParameterised", &setParameterised );
	def( "_parameterisedHolderSetParameterised", &setParameterised2 );
	def( "_parameterisedHolderGetParameterised", &getParameterised );
	def( "_parameterisedHolderSetNodeValues", &setNodeValues );
	def( "_parameterisedHolderSetNodeValue", &setNodeValue );
	def( "_parameterisedHolderSetParameterisedValues", &setParameterisedValues );
	def( "_parameterisedHolderSetParameterisedValue", &setParameterisedValue );
	def( "_parameterisedHolderParameterPlug", &parameterPlug );
	def( "_parameterisedHolderPlugParameter", &plugParameter );

	PointerFromSWIG<MFnDependencyNode>();
	PointerFromSWIG<MPlug>();

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

#include "boost/python.hpp"

#include <cassert>

#include "maya/MFnDependencyNode.h"

#include "IECore/Object.h"
#include "IECore/Parameterised.h"
#include "IECore/bindings/PointerFromSWIG.h"

#include "IECoreMaya/bindings/FnParameterisedHolderBinding.h"
#include "IECoreMaya/StatusException.h"
#include "IECoreMaya/ParameterisedHolder.h"

using namespace IECore;
using namespace IECoreMaya;
using namespace boost::python;

static ParameterisedHolderInterface *interface( MFnDependencyNode *fnDN )
{
	assert( fnDN );

	MPxNode *userNode = fnDN->userNode();
	if( userNode )
	{
		ParameterisedHolderInterface *interface = dynamic_cast<ParameterisedHolderInterface *>( userNode );
		if( interface )
		{
			return interface;
		}
	}
	// failed
	throw Exception( "Not a ParameterisedHolder" );
}

static void setParameterised( MFnDependencyNode *fnDN, ParameterisedPtr p )
{
	assert( fnDN );

	StatusException::throwIfError( interface(fnDN)->setParameterised( p ) );
}

static void setParameterised2( MFnDependencyNode *fnDN, const std::string &className, int classVersion, const std::string &envVarName )
{
	assert( fnDN );

	StatusException::throwIfError( interface(fnDN)->setParameterised( className, classVersion, envVarName ) );
}

static boost::python::tuple getParameterised( MFnDependencyNode *fnDN )
{
	assert( fnDN );

	std::string className; int classVersion = 0; std::string searchPath;
	ParameterisedPtr p = interface( fnDN )->getParameterised( &className, &classVersion, &searchPath );
	return boost::python::make_tuple( p, className, classVersion, searchPath );
}

static void setNodeValues( MFnDependencyNode *fnDN )
{
	assert( fnDN );

	StatusException::throwIfError( interface( fnDN )->setNodeValues() );
}

static void setNodeValue( MFnDependencyNode *fnDN, ParameterPtr pa )
{
	assert( fnDN );

	StatusException::throwIfError( interface( fnDN )->setNodeValue( pa ) );
}

static void setParameterisedValues( MFnDependencyNode *fnDN )
{
	assert( fnDN );

	StatusException::throwIfError( interface( fnDN )->setParameterisedValues() );
}

static void setParameterisedValue( MFnDependencyNode *fnDN, ParameterPtr pa )
{
	assert( fnDN );

	StatusException::throwIfError( interface( fnDN )->setParameterisedValue( pa ) );
}

static std::string parameterPlug( MFnDependencyNode *fnDN, ParameterPtr pa )
{
	assert( fnDN );

	// we don't know how to push a swig wrapped MPlug into python,
	// so we have to push the name and then let the python half of
	// MFnParameterisedHolder construct an MPlug from it.
	MString name = interface( fnDN )->parameterPlug( pa ).name();
	return name.asChar();
}

static ParameterPtr plugParameter( MFnDependencyNode *fnDN, MPlug *plug )
{
	assert( fnDN );

	return interface( fnDN )->plugParameter( *plug );
}

void IECoreMaya::bindFnParameterisedHolder()
{

	def( "_parameterisedHolderSetParameterised", &setParameterised );
	def( "_parameterisedHolderSetParameterised", &setParameterised2 );
	def( "_parameterisedHolderGetParameterised", &getParameterised );
	def( "_parameterisedHolderSetNodeValues", &setNodeValues );
	def( "_parameterisedHolderSetNodeValue", &setNodeValue );
	def( "_parameterisedHolderSetParameterisedValues", &setParameterisedValues );
	def( "_parameterisedHolderSetParameterisedValue", &setParameterisedValue );
	def( "_parameterisedHolderParameterPlug", &parameterPlug );
	def( "_parameterisedHolderPlugParameter", &plugParameter );

	PointerFromSWIG<MFnDependencyNode>();
	PointerFromSWIG<MPlug>();

}
<|endoftext|>


<commit_before>/************************************************************************\
**
**  tUplift.cpp: Functions for class tUplift (see tUplift.h).
**
**  $Id: tUplift.cpp,v 1.6 1999-04-05 15:22:14 gtucker Exp $
\************************************************************************/

#include "tUplift.h"
#include "../errors/errors.h"

#define kNumUpliftTypes 2
#define kNoUplift 0

/************************************************************************\
**
**  tUplift constructor
**
**  Reads in a type code from the input file, then reads parameters
**  needed for the specified type of uplift.
**
**  The current version supports two types of uplift: spatially uniform,
**  and uniform where Y>=Yf (Yf=fault location), zero elsewhere.
**
**  Inputs:  infile -- input file from which to read parameters
**
\************************************************************************/
tUplift::tUplift( tInputFile &infile )
{
   // Find out what kind of uplift the user wants
   typeCode = infile.ReadItem( typeCode, "UPTYPE" );
   if( typeCode < 0 || typeCode > kNumUpliftTypes )
   {
      cerr << "I don't recognize the uplift type you asked for ("
           << typeCode << ")\n";
      cerr << "Valid uplift types are:\n";
      cerr << " 0 - none\n"
           << " 1 - Spatially and temporally uniform uplift\n"
           << " 2 - Uniform uplift at Y >= fault location, zero elsewhere\n";
      ReportFatalError( "Please specify a valid uplift type and try again." );
   }

   if( typeCode==kNoUplift ) return;

   // get the parameters relevant to that type
   duration = infile.ReadItem( duration, "UPDUR" );
   rate = infile.ReadItem( rate, "UPRATE" );
   switch( typeCode )
   {
   case 2:
     faultPosition = infile.ReadItem( faultPosition, "FAULTPOS" );
     break;
   }

}

/************************************************************************\
**
**  tUplift::DoUplift
**
**  Calls the appropriate function to perform the desired type of
**  uplift.
**
**  Inputs:  mp -- pointer to the mesh
**           delt -- duration of uplift
**
\************************************************************************/
void tUplift::DoUplift( tMesh<tLNode> *mp, double delt )
{
   switch( typeCode )
   {
      case 1:
          UpliftUniform( mp, delt );
          break;
      case 2:
          BlockUplift( mp, delt );
          break;
   }

}

/************************************************************************\
**
**  tUplift::UpliftUniform
**
**  Uniform uplift at a constant rate across the entire domain (but not
**  including boundaries).
**
**  Inputs:  mp -- pointer to the mesh
**           delt -- duration of uplift
**
\************************************************************************/
void tUplift::UpliftUniform( tMesh<tLNode> *mp, double delt )
{
   assert( mp>0 );
   tLNode *cn;
   tMeshListIter<tLNode> ni( mp->getNodeList() );
   double rise = rate*delt;

   for( cn=ni.FirstP(); ni.IsActive(); cn=ni.NextP() )
   {
      cn->ChangeZ( rise );
      cn->setUplift( rate );
   }
}

/************************************************************************\
**
**  tUplift::BlockUplift
**
**  Uplift at a constant rate for all points Y>=Yf, where Yf is the
**  location of a vertical fault (striking parallel to x-axis).
**
**  Inputs:  mp -- pointer to the mesh
**           delt -- duration of uplift
**
\************************************************************************/
void tUplift::BlockUplift( tMesh<tLNode> *mp, double delt )
{
   assert( mp>0 );
   tLNode *cn;
   tMeshListIter<tLNode> ni( mp->getNodeList() );
   double rise = rate*delt;

   for( cn=ni.FirstP(); ni.IsActive(); cn=ni.NextP() )
     if( cn->getY()>=faultPosition )
     {
        cn->ChangeZ( rise );
        cn->setUplift( rate );
     }
}

/************************************************************************\
**
**  tUplift "get" functions
**
\************************************************************************/

double tUplift::getDuration()
{
   return duration;
}

double tUplift::getRate() const
{
   return rate;
}

<commit_msg>added "CosineWarp2D" uplift function (GT, May/June 2000)<commit_after>/************************************************************************\
**
**  tUplift.cpp: Functions for class tUplift (see tUplift.h).
**
**  $Id: tUplift.cpp,v 1.7 2000-06-05 12:55:22 gtucker Exp $
\************************************************************************/

#include "tUplift.h"
#include "../errors/errors.h"

#define kNumUpliftTypes 5
#define kNoUplift 0

/************************************************************************\
**
**  tUplift constructor
**
**  Reads in a type code from the input file, then reads parameters
**  needed for the specified type of uplift.
**
**  The current version supports two types of uplift: spatially uniform,
**  and uniform where Y>=Yf (Yf=fault location), zero elsewhere.
**
**  Inputs:  infile -- input file from which to read parameters
**
\************************************************************************/
tUplift::tUplift( tInputFile &infile )
{
   // Find out what kind of uplift the user wants
   typeCode = infile.ReadItem( typeCode, "UPTYPE" );
   if( typeCode < 0 || typeCode > kNumUpliftTypes )
   {
      cerr << "I don't recognize the uplift type you asked for ("
           << typeCode << ")\n";
      cerr << "Valid uplift types are:\n";
      cerr << " 0 - none\n"
           << " 1 - Spatially and temporally uniform uplift\n"
           << " 2 - Uniform uplift at Y >= fault location, zero elsewhere\n"
           << " 3 - Block uplift with strike-slip motion along given Y coord\n"
           << " 4 - Propagating fold modeled w/ simple error function curve\n"
           << " 5 - 2D cosine-based uplift-subsidence pattern\n";
      ReportFatalError( "Please specify a valid uplift type and try again." );
   }

   if( typeCode==kNoUplift ) return;

   // get the parameters relevant to that type
   duration = infile.ReadItem( duration, "UPDUR" );
   rate = infile.ReadItem( rate, "UPRATE" );
   switch( typeCode )
   {
      case 2:
          faultPosition = infile.ReadItem( faultPosition, "FAULTPOS" );
          break;
      case 3:
          faultPosition = infile.ReadItem( faultPosition, "FAULTPOS" );
          slipRate = infile.ReadItem( slipRate, "SLIPRATE" );
          break;
      case 4:
          faultPosition = infile.ReadItem( faultPosition, "FAULTPOS" );
          slipRate = infile.ReadItem( slipRate, "FOLDPROPRATE" );
          foldParam = infile.ReadItem( foldParam, "FOLDWAVELEN" );
          foldParam = 4.0/foldParam;
          break;
      case 5:
          foldParam = infile.ReadItem( foldParam, "FOLDWAVELEN" );
          slipRate = infile.ReadItem( slipRate, "TIGHTENINGRATE" );
          faultPosition = infile.ReadItem( faultPosition, "ANTICLINEYCOORD" );
          break;
   }

}

/************************************************************************\
**
**  tUplift::DoUplift
**
**  Calls the appropriate function to perform the desired type of
**  uplift.
**
**  Inputs:  mp -- pointer to the mesh
**           delt -- duration of uplift
**
\************************************************************************/
void tUplift::DoUplift( tMesh<tLNode> *mp, double delt )
{
   switch( typeCode )
   {
      case 1:
          UpliftUniform( mp, delt );
          break;
      case 2:
          BlockUplift( mp, delt );
          break;
      case 3:
          BlockUplift( mp, delt );
          StrikeSlip( mp, delt );
          break;
      case 4:
          FoldPropErf( mp, delt );
          break;
      case 5:
          CosineWarp2D( mp, delt );
          break;
   }

}

/************************************************************************\
**
**  tUplift::UpliftUniform
**
**  Uniform uplift at a constant rate across the entire domain (but not
**  including boundaries).
**
**  Inputs:  mp -- pointer to the mesh
**           delt -- duration of uplift
**
\************************************************************************/
void tUplift::UpliftUniform( tMesh<tLNode> *mp, double delt )
{
   assert( mp>0 );
   tLNode *cn;
   tMeshListIter<tLNode> ni( mp->getNodeList() );
   double rise = rate*delt;

   //cout << "****UPLIFTUNI: " << rise << endl;

   for( cn=ni.FirstP(); ni.IsActive(); cn=ni.NextP() )
   {
      cn->ChangeZ( rise );
      cn->setUplift( rate );
   }
}

/************************************************************************\
**
**  tUplift::BlockUplift
**
**  Uplift at a constant rate for all points Y>=Yf, where Yf is the
**  location of a vertical fault (striking parallel to x-axis).
**
**  Inputs:  mp -- pointer to the mesh
**           delt -- duration of uplift
**
\************************************************************************/
void tUplift::BlockUplift( tMesh<tLNode> *mp, double delt )
{
   assert( mp>0 );
   tLNode *cn;
   tMeshListIter<tLNode> ni( mp->getNodeList() );
   double rise = rate*delt;

   for( cn=ni.FirstP(); ni.IsActive(); cn=ni.NextP() )
     if( cn->getY()>=faultPosition )
     {
        cn->ChangeZ( rise );
        cn->setUplift( rate );
     }
}

/************************************************************************\
**
**  tUplift::StrikeSlip
**
**  Mesh points at y<faultPosition move to the right relative to other
**  points (ie, left-lateral displacement). Block uplift can also
**  occur (see DoUplift). Note that boundary nodes also move.
**
**  Inputs:  mp -- pointer to the mesh
**           delt -- duration of uplift
**
\************************************************************************/
void tUplift::StrikeSlip( tMesh<tLNode> *mp, double delt )
{
   assert( mp>0 );
   tLNode *cn;
   tMeshListIter<tLNode> ni( mp->getNodeList() );
   double slip = slipRate*delt;

   cout << "StrikeSlip by " << slip << endl;

   for( cn=ni.FirstP(); !(ni.AtEnd()); cn=ni.NextP() )
   {
     if( cn->getY()<faultPosition )
     {
        cn->setMeanderStatus( TRUE );  // redundant: TODO
        cn->setNew2DCoords( cn->getX()+slip, cn->getY() );
     }
   }
   mp->MoveNodes( 0, 0 );

}

/************************************************************************\
**
**  tUplift::FoldPropErf
**
**  This function provides a very simple vertical kinematic
**  representation of fold propagation. Uplift rate is described by
**  a symmetrical error function curve, with uplift on one side
**  (Y>pivot point) and subsidence on the other (relative to fixed
**  boundary elevation). The faultPosition variable is used to track
**  the position of the pivot point, which migrates in the direction
**  of "decreasing Y" at a rate that is stored in "slipRate".
**  The variable foldParam encodes the fold wavelength, which is
**  defined as the distance between the point where uplift comes close
**  to its maximum value (where U = U0 erf(2)) and the point where
**  uplift comes close to its minimum value (where U = U0 erf(-2)).
**  More precisely, foldParam is defined as 4/wavelength.
**
**  Inputs:  mp -- pointer to the mesh
**           delt -- duration of uplift
**
\************************************************************************/
void tUplift::FoldPropErf( tMesh<tLNode> *mp, double delt )
{
   assert( mp>0 );
   tLNode *cn;
   tMeshListIter<tLNode> ni( mp->getNodeList() );
   double uprate;

   // For each node, the uplift rate is the maximum rate ("rate") times
   // the error function curve, which depends on the node's Y-coordinate
   // relative to the pivot point, and on the fold wavelength (the
   // reciprocal of which is embedded in "foldParam"). Note that
   // uplift rate is negative (ie, subsidence occurs) where Y < pivot point.
   for( cn=ni.FirstP(); ni.IsActive(); cn=ni.NextP() )
   {
      uprate = rate * erf( foldParam * ( cn->getY() - faultPosition ) );
      cn->ChangeZ( uprate*delt );
   }

   // Now we "propagate" the fold by moving the pivot point forward
   // (in the direction of decreasing Y coordinate)
   faultPosition -= slipRate * delt;
}

/************************************************************************\
**
**  tUplift::CosineWarp2D
**
**
**  Inputs:  mp -- pointer to the mesh
**           delt -- duration of uplift
**
\************************************************************************/
#define TWOPI 6.2832
void tUplift::CosineWarp2D( tMesh<tLNode> *mp, double delt )
{
   assert( mp>0 );
   tLNode *cn;
   tMeshListIter<tLNode> ni( mp->getNodeList() );
   double uprate;

   // For each node, the uplift rate is the uplift rate constant ("rate") times
   // the cosine function in x and y. Note that the variable "faultPosition"
   // is used to store the Y location of the anticline peak (normally, the
   // upper boundary)
   for( cn=ni.FirstP(); ni.IsActive(); cn=ni.NextP() )
   {
      uprate = rate *
          ( cos(PI*cn->getX()/foldParam)
            + cos(TWOPI*(faultPosition-cn->getY())/foldParam) );
      cn->ChangeZ( uprate*delt );
   }

   // The "tightening" of the folds through time is simulated by
   // progressively decreasing the fold wavelength. (Here the variable
   // "slipRate" is used to store the tightening rate in m/yr, and
   // "foldParam" is used to store the fold wavelength in m).
   // As the fold tightens, the anticline axis migrates in the direction
   // of decreasing Y (assumed to be basinward; this means the folding
   // propagates basinward as it tightens).
   foldParam = foldParam - slipRate*delt;
   faultPosition= faultPosition - slipRate*delt;

}

/************************************************************************\
**
**  tUplift "get" functions
**
\************************************************************************/

double tUplift::getDuration()
{
   return duration;
}

double tUplift::getRate() const
{
   return rate;
}

<|endoftext|>