<commit_before>/**
 * @file csv.cpp
 * @brief CSV file handling.
 *
 * Usage:
 * csv$make takes a settings hash, and produces a CSV object.
 * csv$line handles a line in the CSV, typically read from a file,
 *     and returns a hash, list or none (if header or skip line
 *     was fed in).
 * csv$read reads the entire named file into a list of hashes or lists.
 * csv$cols returns the columns list.
 *
 * Make hash parameters:
 *   `columns is a list of column names, which implies the csv has no header
 *          (default none)
 *   `list if true forces the output to be lists (default false)
 *   `nohead ignores the header even if no col names are given
 *          (names will be invented if the output is a hash)
 *          (default false)
 *   `skip defines a number of lines to ignore at the start (default zero)
 *   `delimiter sets a delimiting character (default ",")
 *   `partial if true will allow rows with less than the number of columns
 *          to be accepted, with list/hash entries created for the number
 *          present. (default false).
 *   `types sets a column type string consisting of the chars "i", "l", "d",
 *          "f" or "s" (int,long,double,float,string). If only one char is
 *          provided, it's used for all cols. Otherwise the char
 *          used is types[colname%strlen(types)]
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>

#include <angort/angort.h>

#include "../hashgets.h"
#include "../wrappers.h"

using namespace angort;

// clear a string list and free all its strings
inline void clearList(ArrayList<char *> *l){
    ArrayListIterator<char*> iter(l);
    for(iter.first();!iter.isDone();iter.next()){
        free(*iter.current());
    }
    l->clear();
}

// temp list used for each line
static ArrayList<char*> list;

// add a new string to the list (takes a length because the list
// may not be null-terminated
void addToList(ArrayList<char *> *l,const char *s,int len){
    char **newfield = l->append();
    char *newstr = (char *)malloc(len+1);
    *newfield = newstr;
    memcpy(newstr,s,len);
    newstr[len]=0;
}

// split a null-terminated line, which must not end in \n.
// If at maxcols, delimiters are ignored.
static ArrayList<char*> *splitLine(const char *s,const char delim,int maxCols=0){
    // we add characters to this as we build up fields, it's
    // the easiest way to do quoting and escaping.
    char *fbuf=(char *)alloca(strlen(s));

    // static list of fields, reused for each line

    clearList(&list);
    // if non-zero, we are in a quoted field
    char quotechar = 0;
    int cols=0;
    char *fptr=fbuf; // field start ptr
    for(;;) {
        // two clauses here:
        // first says "if we're at the last column and the end,
        // fill in the last column." Second says "if columns are free,
        // or we're at or before the second to last column, and there's
        // and end or unquoted delimiter." If either are true, add.
        if(((cols==maxCols-1) && *s==0) || (
              (maxCols==0 || cols<(maxCols-1) ) &&
              (*s==0 || (*s==delim && !quotechar)))){
            // delimiter found, and not in quoted field, and not
            // at maxcolumns. Add string.
            addToList(&list,fbuf,fptr-fbuf);
            cols++;
            fptr=fbuf; // restart field buffer
        } else if(quotechar && *s==quotechar){
            // end of quote
            quotechar=0;
        } else if(*s=='\'' || *s == '\"'){
            // start of quote
            quotechar = *s;
        } else if(*s=='\\') {
            // escape char
            *fptr++ = *++s;
        } else {
            // ordinary char, add to buffer
            *fptr++ = *s;
        }

        if(*s==0)break;
        s++;
    }
    return &list;
}

class CSV  {
    bool noHead; // has no header - either set columns or it will invent them
    int skipLines; // skip N lines
    bool createList; // create lists for each row, not hashes
    bool partial; // permit partial lines
    char delim; // delimiter

    // if true, holds a string of column type chars. These are
    // s=str,f=float,i=int. If missing, all cols are strings.
    // If too short, is modded over i.e. so that a single "f" means all
    // cols are float.
    const char *types;

    int numTypes; // only valid if above is nonnull

    // the actual data, PER LINE. It's either a hash or a list.
    Value linev;

public:
    bool colsGiven; // true if "columns" set, so we don't override them
    int numCols;
    const char **colNames;

    CSV(Hash *h){ // settings hash
        Value *v;
        colNames=NULL;
        if((v=h->getSym("columns"))!=NULL){
            // predefined column headers override those in the file
            ArrayList<Value> *l = Types::tList->get(v);
            numCols = l->count();
            colNames = new const char *[numCols];
            ArrayListIterator<Value> iter(l);
            int i=0;
            for(iter.first();!iter.isDone();iter.next()){
                colNames[i++] = strdup(iter.current()->toString().get());
            }
            colsGiven=true;
        }
        else
            colsGiven=false;

        // do we consider the first line to be just data?
        noHead = hgetintdef(h,"nohead",0)!=0;

        // how many lines at the start do we skip?
        skipLines = hgetintdef(h,"skip",0);

        // do we create a hash for each line, or will a list do?
        createList = hgetintdef(h,"list",0)!=0;

        // delimiter
        delim = hgetstrdef(h,"delimiter",",")[0];

        // partial lines accepted?
        partial = hgetintdef(h,"partial",0)!=0;

        // types
        types = hgetstrdef(h,"types",NULL);
        if(types && !*types)types=NULL; // don't allow empty str.
        if(types){
            types=strdup(types);
            numTypes = strlen(types);
        }
    }

    virtual ~CSV(){
        if(types)
            free((void *)types);
        reset();
    }

    void reset(){
        // do this every time we start a new file, so we can
        // get a new set of column names (and not read the first
        // line of the subsequent files as a line of data)
        if(colNames && !colsGiven){
            for(int i=0;i<numCols;i++)
                if(colNames[i])free((void *)colNames[i]);
            delete [] colNames;
            colNames=NULL;
        }
    }

    // process a line of input and set the value accordingly. Will throw
    // away items created from partial output if "partial" is not set
    void line(Value *linev,const char *s){
        int numitems=0;

        // are we skipping?
        if(skipLines && skipLines--){
            linev->clr();
            return;
        }

        if(!colNames && noHead){
            // no colnames and no head! We'll have to invent something.
            // we end up doing this twice, but it's only on the first line
            ArrayList<char *> *l = splitLine(s,delim,numCols);
            numCols = l->count();
            colNames = new const char *[numCols];
            for(int i=0;i<numCols;i++){
                char buf[256];
                sprintf(buf,"V%d",i);
                colNames[i]=strdup(buf);
            }
        }

        if(!colNames){ // no col names, but we are allowed a header
            //no, extract them
            ArrayList<char *> *l = splitLine(s,delim,0);
            numCols = l->count();
            colNames = new const char *[numCols];
            ArrayListIterator<char*> iter(l);
            int i=0;
            for(iter.first();!iter.isDone();iter.next(),i++){
                if(!strlen(*iter.current())){
                    char buf[256];
                    sprintf(buf,"V%d",i);
                    colNames[i] = strdup(buf);
                } else
                    colNames[i] = strdup(*iter.current());
            }
        } else {
            ArrayList<char *> *l = splitLine(s,delim,numCols);
            if(createList){
                ArrayList<Value> *out = Types::tList->set(linev);
                ArrayListIterator<char*> iter(l);
                int i=0;
                for(iter.first();!iter.isDone();iter.next(),i++){
                    char *s = *iter.current();
                    Value *vout = out->append();
                    numitems++;
                    if(types){
                        switch(types[i%numTypes]){
                        case 'i':
                            Types::tInteger->set(vout,atoi(s));
                            break;
			case 'l':
			    Types::tLong->set(vout,atol(s));
			    break;
                        case 'f':
                            Types::tFloat->set(vout,atof(s));
                            break;
                        case 'd':
                            Types::tDouble->set(vout,atof(s));
                            break;
                        case 's':
                        default:
                            Types::tString->set(vout,s);
                            break;
                        }
                    } else {
                        Types::tString->set(vout,s);
                    }
                }
            } else {
                Hash *out = Types::tHash->set(linev);
                ArrayListIterator<char*> iter(l);
                int i=0;
                for(iter.first();!iter.isDone();iter.next(),i++){
                    char *s = *iter.current();
                    Value vout;
                    if(types){
                        switch(types[i%numTypes]){
                        case 'i':
                            Types::tInteger->set(&vout,atoi(s));
                            break;
                        case 'f':
                            Types::tFloat->set(&vout,atof(s));
                            break;
                        case 's':
                        default:
                            Types::tString->set(&vout,s);
                            break;
                        }
                    } else {
                        Types::tString->set(&vout,s);
                    }
                    out->setSym(colNames[i],&vout);
                    numitems++;
                }
            }
        }
        // if we didn't get at least the right number of items,
        // ignore what we just read. Of course, numitems is never
        // greater than cols because of lines being split into at
        // maximum cols columns.
        if(!partial && (numitems != numCols))
            linev->clr();
    }
};

static WrapperType<CSV> tCSV("CSVT");

%type csv tCSV CSV

%name csv
%shared

%wordargs make h (hash -- csv) start a new CSV object, given settings for reading
{
    CSV *c = new CSV(p0);
    tCSV.set(a->pushval(),c);
}

%wordargs line sA|csv (s csv -- val) parse a line, producing a hash or a list, or none if this was a skip or column header line.
{
    Value v;
    p1->line(&v,p0);
    a->pushval()->copy(&v);
}

%wordargs read As|csv (csv filename -- list|none) parse an entire file
{
    FILE *f = fopen(p1,"r");
    if(!f){
        a->pushNone();
    } else {
        p0->reset();
        Value listv,linev;
        ArrayList<Value> *list=Types::tList->set(&listv);
        char buf[8192];
        while(fgets(buf,8192,f)){
            int l=strlen(buf);
            if(l){
                buf[l-1]=0;
                p0->line(&linev,buf);
                if(!linev.isNone()){
                    list->append()->copy(&linev);
                }
            }
        }
        fclose(f);
        a->pushval()->copy(&listv);
    }
}

%wordargs reset A|csv (csv -- ) reset the CSV reader
Resets the CSV reader given, so that it will parse headers as the next
line.
{
    p0->reset();
}

%wordargs cols A|csv (csv -- list|none) get list of cols if present, or none.
{
    if(!p0->colNames){
        a->pushNone();
    } else {
        ArrayList<Value> *out = Types::tList->set(a->pushval());
        for(int i=0;i<p0->numCols;i++){
            Value *v = out->append();
            Types::tString->set(v,p0->colNames[i]);
        }
    }

}

%wordargs parseline si (s maxcols -- list) parse a single comma-separated line
{
    Value v;
    ArrayList<Value> *out = Types::tList->set(&v);
    ArrayList<char *> *list = splitLine(p0,',',p1);

    ArrayListIterator<char*> iter(list);
    for(iter.first();!iter.isDone();iter.next()){
        Value *vv = out->append();
        Types::tString->set(vv,*iter.current());
    }
    a->pushval()->copy(&v);
}

%init
{
    fprintf(stderr,"Initialising CSV plugin, %s %s\n",__DATE__,__TIME__);
}

<commit_msg>csv bug: longs/doubles in hash column types work<commit_after>/**
 * @file csv.cpp
 * @brief CSV file handling.
 *
 * Usage:
 * csv$make takes a settings hash, and produces a CSV object.
 * csv$line handles a line in the CSV, typically read from a file,
 *     and returns a hash, list or none (if header or skip line
 *     was fed in).
 * csv$read reads the entire named file into a list of hashes or lists.
 * csv$cols returns the columns list.
 *
 * Make hash parameters:
 *   `columns is a list of column names, which implies the csv has no header
 *          (default none)
 *   `list if true forces the output to be lists (default false)
 *   `nohead ignores the header even if no col names are given
 *          (names will be invented if the output is a hash)
 *          (default false)
 *   `skip defines a number of lines to ignore at the start (default zero)
 *   `delimiter sets a delimiting character (default ",")
 *   `partial if true will allow rows with less than the number of columns
 *          to be accepted, with list/hash entries created for the number
 *          present. (default false).
 *   `types sets a column type string consisting of the chars "i", "l", "d",
 *          "f" or "s" (int,long,double,float,string). If only one char is
 *          provided, it's used for all cols. Otherwise the char
 *          used is types[colname%strlen(types)]
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>

#include <angort/angort.h>

#include "../hashgets.h"
#include "../wrappers.h"

using namespace angort;

// clear a string list and free all its strings
inline void clearList(ArrayList<char *> *l){
    ArrayListIterator<char*> iter(l);
    for(iter.first();!iter.isDone();iter.next()){
        free(*iter.current());
    }
    l->clear();
}

// temp list used for each line
static ArrayList<char*> list;

// add a new string to the list (takes a length because the list
// may not be null-terminated
void addToList(ArrayList<char *> *l,const char *s,int len){
    char **newfield = l->append();
    char *newstr = (char *)malloc(len+1);
    *newfield = newstr;
    memcpy(newstr,s,len);
    newstr[len]=0;
}

// split a null-terminated line, which must not end in \n.
// If at maxcols, delimiters are ignored.
static ArrayList<char*> *splitLine(const char *s,const char delim,int maxCols=0){
    // we add characters to this as we build up fields, it's
    // the easiest way to do quoting and escaping.
    char *fbuf=(char *)alloca(strlen(s));

    // static list of fields, reused for each line

    clearList(&list);
    // if non-zero, we are in a quoted field
    char quotechar = 0;
    int cols=0;
    char *fptr=fbuf; // field start ptr
    for(;;) {
        // two clauses here:
        // first says "if we're at the last column and the end,
        // fill in the last column." Second says "if columns are free,
        // or we're at or before the second to last column, and there's
        // and end or unquoted delimiter." If either are true, add.
        if(((cols==maxCols-1) && *s==0) || (
              (maxCols==0 || cols<(maxCols-1) ) &&
              (*s==0 || (*s==delim && !quotechar)))){
            // delimiter found, and not in quoted field, and not
            // at maxcolumns. Add string.
            addToList(&list,fbuf,fptr-fbuf);
            cols++;
            fptr=fbuf; // restart field buffer
        } else if(quotechar && *s==quotechar){
            // end of quote
            quotechar=0;
        } else if(*s=='\'' || *s == '\"'){
            // start of quote
            quotechar = *s;
        } else if(*s=='\\') {
            // escape char
            *fptr++ = *++s;
        } else {
            // ordinary char, add to buffer
            *fptr++ = *s;
        }

        if(*s==0)break;
        s++;
    }
    return &list;
}

class CSV  {
    bool noHead; // has no header - either set columns or it will invent them
    int skipLines; // skip N lines
    bool createList; // create lists for each row, not hashes
    bool partial; // permit partial lines
    char delim; // delimiter

    // if true, holds a string of column type chars. These are
    // s=str,f=float,i=int. If missing, all cols are strings.
    // If too short, is modded over i.e. so that a single "f" means all
    // cols are float.
    const char *types;

    int numTypes; // only valid if above is nonnull

    // the actual data, PER LINE. It's either a hash or a list.
    Value linev;

public:
    bool colsGiven; // true if "columns" set, so we don't override them
    int numCols;
    const char **colNames;

    CSV(Hash *h){ // settings hash
        Value *v;
        colNames=NULL;
        if((v=h->getSym("columns"))!=NULL){
            // predefined column headers override those in the file
            ArrayList<Value> *l = Types::tList->get(v);
            numCols = l->count();
            colNames = new const char *[numCols];
            ArrayListIterator<Value> iter(l);
            int i=0;
            for(iter.first();!iter.isDone();iter.next()){
                colNames[i++] = strdup(iter.current()->toString().get());
            }
            colsGiven=true;
        }
        else
            colsGiven=false;

        // do we consider the first line to be just data?
        noHead = hgetintdef(h,"nohead",0)!=0;

        // how many lines at the start do we skip?
        skipLines = hgetintdef(h,"skip",0);

        // do we create a hash for each line, or will a list do?
        createList = hgetintdef(h,"list",0)!=0;

        // delimiter
        delim = hgetstrdef(h,"delimiter",",")[0];

        // partial lines accepted?
        partial = hgetintdef(h,"partial",0)!=0;

        // types
        types = hgetstrdef(h,"types",NULL);
        if(types && !*types)types=NULL; // don't allow empty str.
        if(types){
            types=strdup(types);
            numTypes = strlen(types);
        }
    }

    virtual ~CSV(){
        if(types)
            free((void *)types);
        reset();
    }

    void reset(){
        // do this every time we start a new file, so we can
        // get a new set of column names (and not read the first
        // line of the subsequent files as a line of data)
        if(colNames && !colsGiven){
            for(int i=0;i<numCols;i++)
                if(colNames[i])free((void *)colNames[i]);
            delete [] colNames;
            colNames=NULL;
        }
    }

    // process a line of input and set the value accordingly. Will throw
    // away items created from partial output if "partial" is not set
    void line(Value *linev,const char *s){
        int numitems=0;

        // are we skipping?
        if(skipLines && skipLines--){
            linev->clr();
            return;
        }

        if(!colNames && noHead){
            // no colnames and no head! We'll have to invent something.
            // we end up doing this twice, but it's only on the first line
            ArrayList<char *> *l = splitLine(s,delim,numCols);
            numCols = l->count();
            colNames = new const char *[numCols];
            for(int i=0;i<numCols;i++){
                char buf[256];
                sprintf(buf,"V%d",i);
                colNames[i]=strdup(buf);
            }
        }

        if(!colNames){ // no col names, but we are allowed a header
            //no, extract them
            ArrayList<char *> *l = splitLine(s,delim,0);
            numCols = l->count();
            colNames = new const char *[numCols];
            ArrayListIterator<char*> iter(l);
            int i=0;
            for(iter.first();!iter.isDone();iter.next(),i++){
                if(!strlen(*iter.current())){
                    char buf[256];
                    sprintf(buf,"V%d",i);
                    colNames[i] = strdup(buf);
                } else
                    colNames[i] = strdup(*iter.current());
            }
        } else {
            ArrayList<char *> *l = splitLine(s,delim,numCols);
            if(createList){
                ArrayList<Value> *out = Types::tList->set(linev);
                ArrayListIterator<char*> iter(l);
                int i=0;
                for(iter.first();!iter.isDone();iter.next(),i++){
                    char *s = *iter.current();
                    Value *vout = out->append();
                    numitems++;
                    if(types){
                        switch(types[i%numTypes]){
                        case 'i':
                            Types::tInteger->set(vout,atoi(s));
                            break;
			case 'l':
			    Types::tLong->set(vout,atol(s));
			    break;
                        case 'f':
                            Types::tFloat->set(vout,atof(s));
                            break;
                        case 'd':
                            Types::tDouble->set(vout,atof(s));
                            break;
                        case 's':
                        default:
                            Types::tString->set(vout,s);
                            break;
                        }
                    } else {
                        Types::tString->set(vout,s);
                    }
                }
            } else {
                Hash *out = Types::tHash->set(linev);
                ArrayListIterator<char*> iter(l);
                int i=0;
                for(iter.first();!iter.isDone();iter.next(),i++){
                    char *s = *iter.current();
                    Value vout;
                    if(types){
                        switch(types[i%numTypes]){
                        case 'i':
                            Types::tInteger->set(&vout,atoi(s));
                            break;
			case 'l':
			    Types::tLong->set(&vout,atol(s));
			    break;
                        case 'f':
                            Types::tFloat->set(&vout,atof(s));
                            break;
                        case 'd':
                            Types::tDouble->set(&vout,atof(s));
                            break;
                        case 's':
                        default:
                            Types::tString->set(&vout,s);
                            break;
                        }
                    } else {
                        Types::tString->set(&vout,s);
                    }
                    out->setSym(colNames[i],&vout);
                    numitems++;
                }
            }
        }
        // if we didn't get at least the right number of items,
        // ignore what we just read. Of course, numitems is never
        // greater than cols because of lines being split into at
        // maximum cols columns.
        if(!partial && (numitems != numCols))
            linev->clr();
    }
};

static WrapperType<CSV> tCSV("CSVT");

%type csv tCSV CSV

%name csv
%shared

%wordargs make h (hash -- csv) start a new CSV object, given settings for reading
{
    CSV *c = new CSV(p0);
    tCSV.set(a->pushval(),c);
}

%wordargs line sA|csv (s csv -- val) parse a line, producing a hash or a list, or none if this was a skip or column header line.
{
    Value v;
    p1->line(&v,p0);
    a->pushval()->copy(&v);
}

%wordargs read As|csv (csv filename -- list|none) parse an entire file
{
    FILE *f = fopen(p1,"r");
    if(!f){
        a->pushNone();
    } else {
        p0->reset();
        Value listv,linev;
        ArrayList<Value> *list=Types::tList->set(&listv);
        char buf[8192];
        while(fgets(buf,8192,f)){
            int l=strlen(buf);
            if(l){
                buf[l-1]=0;
                p0->line(&linev,buf);
                if(!linev.isNone()){
                    list->append()->copy(&linev);
                }
            }
        }
        fclose(f);
        a->pushval()->copy(&listv);
    }
}

%wordargs reset A|csv (csv -- ) reset the CSV reader
Resets the CSV reader given, so that it will parse headers as the next
line.
{
    p0->reset();
}

%wordargs cols A|csv (csv -- list|none) get list of cols if present, or none.
{
    if(!p0->colNames){
        a->pushNone();
    } else {
        ArrayList<Value> *out = Types::tList->set(a->pushval());
        for(int i=0;i<p0->numCols;i++){
            Value *v = out->append();
            Types::tString->set(v,p0->colNames[i]);
        }
    }

}

%wordargs parseline si (s maxcols -- list) parse a single comma-separated line
{
    Value v;
    ArrayList<Value> *out = Types::tList->set(&v);
    ArrayList<char *> *list = splitLine(p0,',',p1);

    ArrayListIterator<char*> iter(list);
    for(iter.first();!iter.isDone();iter.next()){
        Value *vv = out->append();
        Types::tString->set(vv,*iter.current());
    }
    a->pushval()->copy(&v);
}

%init
{
    fprintf(stderr,"Initialising CSV plugin, %s %s\n",__DATE__,__TIME__);
}

<|endoftext|>


<commit_before><commit_msg>[C++] empty class.<commit_after><|endoftext|>


<commit_before>#include "reader.hpp"

// #include "rt/core.hpp"
#include "values.hpp"
#include "core.hpp"

#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <vector>

using namespace rev;
using namespace rev::rdr;

enum class parse_state_t {
  pass,
  skip,
  fail
};

typedef std::tuple<parse_state_t, value_t::p> result_t;

typedef std::vector<value_t::p> values_t;

typedef std::function<result_t (std::istream&)> macro_t;
typedef std::map<char, macro_t> macros_t;

typedef std::function<result_t (std::istream&)> pass_t;
typedef std::vector<pass_t> passes_t;

typedef std::function<
    value_t::p (const std::string&)
  > ctor_t;

typedef std::function<
    value_t::p (const values_t&)
  > from_list_t;

template<typename T>
macro_t  balanced_form(char until);
macro_t  expand(const macro_t& m);
macro_t  wrap(const char*);
result_t read_or_skip(std::istream& in);
result_t conditional(std::istream& in);
result_t drop(std::istream& in);
result_t meta(std::istream& in);
result_t syntax_quote(std::istream& in);
result_t unquote(std::istream& in);
result_t unbalanced_error(std::istream& in);
result_t read_string(std::istream& in);
result_t read_symbol(std::istream& in);
result_t read_keyword(std::istream& in);
result_t consult_table(std::istream& in);
void     skip_white_space(std::istream& in);
void     skip_comment(std::istream& in);

static sym_t::p QUOTE   = sym_t::intern("quote");
static sym_t::p UNQUOTE = sym_t::intern("unquote");
static sym_t::p SPLICE  = sym_t::intern("unquote-splicing");
static sym_t::p SEQ     = sym_t::intern("seq");
static sym_t::p APPLY   = sym_t::intern("apply");
static sym_t::p LIST    = sym_t::intern("list");
static sym_t::p VECTOR  = sym_t::intern("vector");
static sym_t::p HMAP    = sym_t::intern("hash-map");
static sym_t::p CONCAT  = sym_t::intern("concat");

static macros_t extensions(
  {{'{', balanced_form<set_t>('}')},
   {'?', conditional},
   {'_', drop}});

static macros_t macros(
  {{'(',  balanced_form<list_t>(')')},
   {'[',  balanced_form<vector_t>(']')},
   {'{',  balanced_form<map_t>('}')},
   {'\"', read_string},
   // before loading the keyword name space, we treat keywords as regular
   // symbols so that name(kw) returns a string that doesn't contain the
   // colon like name would on a keyword
   {':',  read_keyword},
   {'@',  wrap("deref")},
   {'\'', wrap("quote")},
   {'`',  syntax_quote},
   {'~',  unquote},
   {'^',  meta},
   {'#',  consult_table},
   {')',  unbalanced_error},
   {']',  unbalanced_error}});

inline result_t pass(const value_t::p& v) {
  return std::make_tuple(parse_state_t::pass, v);
}

inline result_t skip() {
  return std::make_tuple(parse_state_t::skip, nullptr);
}

inline result_t fail() {
  return std::make_tuple(parse_state_t::fail, value_t::p());
}

macro_t list_reader(char until, const from_list_t& ctor) {
  return [=](std::istream& in) {

    values_t objs;
    bool terminate = false;

    while (!terminate) {
      // skip whitespace before reading next list element
      // to catch cases like:
      // (list a b
      //   )
      skip_white_space(in);
      skip_comment(in);

      char c = in.peek();

      if (c == std::char_traits<char>::eof()) {
        throw eos();
      }
      else if (c == until) {
        in.get();
        terminate = true;
      }
      else {
        auto result = read_or_skip(in);
        if (std::get<0>(result) != parse_state_t::skip) {
          objs.push_back(std::get<1>(result));
        }
      }
    }

    return pass(ctor(objs));
  };
}

template<typename T>
macro_t balanced_form(char until) {
  return list_reader(until, [](const values_t& objs) {
      return T::from_std(objs);
  });
}

macro_t wrap(const char* s) {

  std::string sym(s);

  return [sym](std::istream& in) {

    values_t forms({
      sym_t::intern(sym),
        read(in)
      });

    return pass(list_t::from_std(forms));
  };
}

result_t conditional(std::istream& in) {

  static const keyw_t::p REV = keyw_t::intern("rev");
  static const keyw_t::p DEF = keyw_t::intern("default");

  auto branches = imu::partition<list_t::p>(2, as<list_t>(read(in)));

  value_t::p form = nullptr, def = nullptr;
  while (!imu::is_empty(branches)) {
    auto kv = as<list_t>(imu::first(branches));
    auto k  = as<keyw_t>(imu::first(kv));

    if (k == REV) {
      form = *imu::second(kv);
      break;
    }
    else if (k == DEF) {
      def = *imu::second(kv);
    }
    branches = imu::rest(branches);
  }

  if (form || def) {
    return form ? pass(form) : pass(def);
  }

  return skip();
}

result_t drop(std::istream& in) {
  // read two forms and return the second
  read(in);
  return skip();
}

result_t meta(std::istream& in) {
  // read two forms and return the second
  auto meta = read(in);
  auto form = read(in);

  map_t::p m;

  if (auto sym = as_nt<keyw_t>(meta)) {
    m = imu::assoc(imu::nu<map_t>(), sym, sym_t::true_);
  }
  else if (auto m2 = as_nt<map_t>(meta)) {
    m = m2;
  }

  if (m) {
    void* args[] = {(void*) form, (void*) m};
    form = protocol_t::dispatch(protocol_t::withmeta, 0, args, 2);
  }

  return pass(form);
}

value_t::p do_syntax_quote(const value_t::p& form);

template<typename S>
list_t::p expand_seq(const S& s) {

  std::vector<value_t::p> out;

  imu::for_each([&](const value_t::p& v) {
    auto lst = as_nt<list_t>(v);
    auto sym = as_nt<sym_t>(imu::first(lst));
    if (sym && sym == UNQUOTE) {
      out.push_back(list_t::factory(LIST, *imu::second(lst)));
    }
    else if (sym && sym == SPLICE) {
      out.push_back(*imu::second(lst));
    }
    else {
      out.push_back(list_t::factory(LIST, do_syntax_quote(v)));
    }
  }, s);

  return list_t::from_std(out);
}

value_t::p do_syntax_quote(const value_t::p& form) {
  if (auto sym = as_nt<sym_t>(form)) {
    auto mangled = sym;
    if (sym->name().back() != '#') {
      mangled = qualify(sym);
    }
    // TODO: handle # symbols
    return list_t::factory(QUOTE, mangled);
  }
  else if (auto lst = as_nt<list_t>(form)) {
    if (auto s = imu::seq(lst)) {
      return list_t::factory(SEQ, imu::conj(expand_seq(s), CONCAT));
    }
    else {
      return imu::nu<list_t>();
    }
  }
  else if (auto vec = as_nt<vector_t>(form)) {
    return list_t::factory(APPLY, VECTOR, imu::conj(expand_seq(seq(vec)), CONCAT));
  }
  else if (auto map = as_nt<map_t>(form)) {
    return list_t::factory(APPLY, HMAP, imu::conj(expand_seq(seq(vec)), CONCAT));
  }
  else if (is<int_t>(form) || is<string_t>(form)) {
    return form;
  }

  return list_t::factory(QUOTE, form);
}

result_t syntax_quote(std::istream& in) {
  return pass(do_syntax_quote(read(in)));
}

result_t unquote(std::istream& in) {

  std::string quote =
    (in.peek() == '@') ? (in.get(), "unquote-splicing") : "unquote";

  values_t forms({
    sym_t::intern(quote),
    read(in)
  });

  return pass(list_t::from_std(forms));
}

std::string escape(const std::string& s) {

  std::string out;

  auto i = s.begin();
  auto j = i;

  while (i != s.end()) {
    if (*(i++) == '\\') {
      if (i == s.end()) {
        throw std::runtime_error(
          "Incomplete escape sequence at thend of string");
      }
      out.append(j, i-1);
      switch(*i) {
      case '0':  out += '\0'; break;
      case 'n':  out += '\n'; break;
      case 'r':  out += '\r'; break;
      case 't':  out += '\t'; break;
      case '\\': out += '\\'; break;
      default:
        throw std::runtime_error(
          std::string("Unsupported escape sequence: \\") + *i);
      }
      j = ++i;
    }
  }

  out.append(j, i);

  return out;
}

macro_t string_reader(const ctor_t& ctor) {
  return [=](std::istream& in) {
    std::string str;
    std::getline(in, str, '\"');

    if (in.eof()) {
      throw unbalanced('\"');
    }

    return pass(ctor(escape(str)));
  };
}

result_t read_string(std::istream& in) {
  static const auto read = string_reader([](const std::string& s) {
      return string_t::intern(s);
  });
  return read(in);
}

result_t try_macros(std::istream& in, const macros_t& macs) {

  result_t res = fail();

  auto iter = macs.find(in.peek());
  if (iter != macs.end()) {
    in.get();
    res = iter->second(in);
  }

  return res;
}

result_t unbalanced_error(std::istream& in) {
  throw unbalanced(in.peek());
}

result_t consult_table(std::istream& in) {
  return try_macros(in, extensions);
}

result_t try_default_macros(std::istream& in) {
  return try_macros(in, macros);
}

bool is_sym_token(char c) {
  return
    (c != std::char_traits<char>::eof())
    && (!isspace(c))
    && (c != ')') && (c != '}') && (c != ']')
    //&& (macros.find(c) == macros.end())
    ;
}

macro_t symbol_reader(const ctor_t& ctor) {
  return [=](std::istream& in){
    char c = in.peek();
    if (is_sym_token(c)) {

      std::string sym;

      do {

        sym += in.get();
        c = in.peek();

      } while(is_sym_token(c));

      return pass(ctor(sym));
    }

    return fail();
  };
}

result_t read_symbol(std::istream& in) {
  static const auto read = symbol_reader([](const std::string& s){
      if (s == "nil") {
        return sym_t::p();
      }
      return sym_t::intern(s);
    });
  return read(in);
}

result_t read_keyword(std::istream& in) {
  static const auto read = symbol_reader([](const std::string& s){
      if (s.size() > 0 && s[0] == ':') {
        return keyw_t::intern(ns()->name() + "/"  + s.substr(1));
      }
      return keyw_t::intern(s);
    });
  return read(in);
}

result_t try_number(std::istream& in) {

  std::string s;

  if (!isdigit(in.peek())) {
    if (in.peek() == '-') {
      s += in.get();
      if (!isdigit(in.peek())) {
        in.putback('-');
        return fail();
      }
    }
    else {
      return fail();
    }
  }

  do {
    s += in.get();
  } while (isalnum(in.peek()));

  return pass(imu::nu<int_t>(std::stoll(s, nullptr, 0)));
}

void skip_white_space(std::istream& in) {

  char c = in.peek();
  while(isspace(c)) {

    in.get();
    c = in.peek();
  }
}

void skip_comment(std::istream& in) {

  while (in.peek() == ';') {
    do {
      in.get();
    } while (in.peek() != '\n');
    skip_white_space(in);
  }
}

result_t read_or_skip(std::istream& in) {

  skip_white_space(in);
  skip_comment(in);

  if (in.eof()) {
    return pass(nullptr);
  }

  passes_t passes({
      &try_number
    , &try_default_macros
    , &read_symbol});

  result_t res = fail();

  for(auto x : passes) {
    res = x(in);
    if(std::get<0>(res) != parse_state_t::fail) {
      break;
    }
  }

  if (std::get<0>(res) == parse_state_t::fail) {
    throw std::runtime_error("Unable to parse form");
  }

  return res;
}

value_t::p rev::rdr::read(std::istream& in) {
  auto result = read_or_skip(in);
  if (std::get<0>(result) == parse_state_t::pass) {
    return std::get<1>(result);
  }
  return nullptr;
}

value_t::p rev::rdr::read(const std::string& s) {
  std::stringstream in(s);
  return read(in);
}

void set_macro(char begin, const macro_t& reader) {
  macros[begin] = [=](std::istream& in) {
    return reader(in);
  };
}

void push_macro_table(char begin, const macro_t& reader) {
  extensions[begin] = reader;
}
<commit_msg>Parse char literals<commit_after>#include "reader.hpp"

// #include "rt/core.hpp"
#include "values.hpp"
#include "core.hpp"

#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <vector>

using namespace rev;
using namespace rev::rdr;

enum class parse_state_t {
  pass,
  skip,
  fail
};

typedef std::tuple<parse_state_t, value_t::p> result_t;

typedef std::vector<value_t::p> values_t;

typedef std::function<result_t (std::istream&)> macro_t;
typedef std::map<char, macro_t> macros_t;

typedef std::function<result_t (std::istream&)> pass_t;
typedef std::vector<pass_t> passes_t;

typedef std::function<
    value_t::p (const std::string&)
  > ctor_t;

typedef std::function<
    value_t::p (const values_t&)
  > from_list_t;

template<typename T>
macro_t  balanced_form(char until);
macro_t  expand(const macro_t& m);
macro_t  wrap(const char*);
result_t read_or_skip(std::istream& in);
result_t conditional(std::istream& in);
result_t drop(std::istream& in);
result_t meta(std::istream& in);
result_t syntax_quote(std::istream& in);
result_t unquote(std::istream& in);
result_t unbalanced_error(std::istream& in);
result_t read_char(std::istream& in);
result_t read_string(std::istream& in);
result_t read_symbol(std::istream& in);
result_t read_keyword(std::istream& in);
result_t consult_table(std::istream& in);
void     skip_white_space(std::istream& in);
void     skip_comment(std::istream& in);

static sym_t::p QUOTE   = sym_t::intern("quote");
static sym_t::p UNQUOTE = sym_t::intern("unquote");
static sym_t::p SPLICE  = sym_t::intern("unquote-splicing");
static sym_t::p SEQ     = sym_t::intern("seq");
static sym_t::p APPLY   = sym_t::intern("apply");
static sym_t::p LIST    = sym_t::intern("list");
static sym_t::p VECTOR  = sym_t::intern("vector");
static sym_t::p HMAP    = sym_t::intern("hash-map");
static sym_t::p CONCAT  = sym_t::intern("concat");

static macros_t extensions(
  {{'{', balanced_form<set_t>('}')},
   {'?', conditional},
   {'_', drop}});

static macros_t macros(
  {{'(',  balanced_form<list_t>(')')},
   {'[',  balanced_form<vector_t>(']')},
   {'{',  balanced_form<map_t>('}')},
   {'\\', read_char},
   {'\"', read_string},
   // before loading the keyword name space, we treat keywords as regular
   // symbols so that name(kw) returns a string that doesn't contain the
   // colon like name would on a keyword
   {':',  read_keyword},
   {'@',  wrap("deref")},
   {'\'', wrap("quote")},
   {'`',  syntax_quote},
   {'~',  unquote},
   {'^',  meta},
   {'#',  consult_table},
   {')',  unbalanced_error},
   {']',  unbalanced_error}});

inline result_t pass(const value_t::p& v) {
  return std::make_tuple(parse_state_t::pass, v);
}

inline result_t skip() {
  return std::make_tuple(parse_state_t::skip, nullptr);
}

inline result_t fail() {
  return std::make_tuple(parse_state_t::fail, value_t::p());
}

macro_t list_reader(char until, const from_list_t& ctor) {
  return [=](std::istream& in) {

    values_t objs;
    bool terminate = false;

    while (!terminate) {
      // skip whitespace before reading next list element
      // to catch cases like:
      // (list a b
      //   )
      skip_white_space(in);
      skip_comment(in);

      char c = in.peek();

      if (c == std::char_traits<char>::eof()) {
        throw eos();
      }
      else if (c == until) {
        in.get();
        terminate = true;
      }
      else {
        auto result = read_or_skip(in);
        if (std::get<0>(result) != parse_state_t::skip) {
          objs.push_back(std::get<1>(result));
        }
      }
    }

    return pass(ctor(objs));
  };
}

template<typename T>
macro_t balanced_form(char until) {
  return list_reader(until, [](const values_t& objs) {
      return T::from_std(objs);
  });
}

macro_t wrap(const char* s) {

  std::string sym(s);

  return [sym](std::istream& in) {

    values_t forms({
      sym_t::intern(sym),
        read(in)
      });

    return pass(list_t::from_std(forms));
  };
}

result_t conditional(std::istream& in) {

  static const keyw_t::p REV = keyw_t::intern("rev");
  static const keyw_t::p DEF = keyw_t::intern("default");

  auto branches = imu::partition<list_t::p>(2, as<list_t>(read(in)));

  value_t::p form = nullptr, def = nullptr;
  while (!imu::is_empty(branches)) {
    auto kv = as<list_t>(imu::first(branches));
    auto k  = as<keyw_t>(imu::first(kv));

    if (k == REV) {
      form = *imu::second(kv);
      break;
    }
    else if (k == DEF) {
      def = *imu::second(kv);
    }
    branches = imu::rest(branches);
  }

  if (form || def) {
    return form ? pass(form) : pass(def);
  }

  return skip();
}

result_t drop(std::istream& in) {
  // read two forms and return the second
  read(in);
  return skip();
}

result_t meta(std::istream& in) {
  // read two forms and return the second
  auto meta = read(in);
  auto form = read(in);

  map_t::p m;

  if (auto sym = as_nt<keyw_t>(meta)) {
    m = imu::assoc(imu::nu<map_t>(), sym, sym_t::true_);
  }
  else if (auto m2 = as_nt<map_t>(meta)) {
    m = m2;
  }

  if (m) {
    void* args[] = {(void*) form, (void*) m};
    form = protocol_t::dispatch(protocol_t::withmeta, 0, args, 2);
  }

  return pass(form);
}

value_t::p do_syntax_quote(const value_t::p& form);

template<typename S>
list_t::p expand_seq(const S& s) {

  std::vector<value_t::p> out;

  imu::for_each([&](const value_t::p& v) {
    auto lst = as_nt<list_t>(v);
    auto sym = as_nt<sym_t>(imu::first(lst));
    if (sym && sym == UNQUOTE) {
      out.push_back(list_t::factory(LIST, *imu::second(lst)));
    }
    else if (sym && sym == SPLICE) {
      out.push_back(*imu::second(lst));
    }
    else {
      out.push_back(list_t::factory(LIST, do_syntax_quote(v)));
    }
  }, s);

  return list_t::from_std(out);
}

value_t::p do_syntax_quote(const value_t::p& form) {
  if (auto sym = as_nt<sym_t>(form)) {
    auto mangled = sym;
    if (sym->name().back() != '#') {
      mangled = qualify(sym);
    }
    // TODO: handle # symbols
    return list_t::factory(QUOTE, mangled);
  }
  else if (auto lst = as_nt<list_t>(form)) {
    if (auto s = imu::seq(lst)) {
      return list_t::factory(SEQ, imu::conj(expand_seq(s), CONCAT));
    }
    else {
      return imu::nu<list_t>();
    }
  }
  else if (auto vec = as_nt<vector_t>(form)) {
    return list_t::factory(APPLY, VECTOR, imu::conj(expand_seq(seq(vec)), CONCAT));
  }
  else if (auto map = as_nt<map_t>(form)) {
    return list_t::factory(APPLY, HMAP, imu::conj(expand_seq(seq(vec)), CONCAT));
  }
  else if (is<int_t>(form) || is<string_t>(form)) {
    return form;
  }

  return list_t::factory(QUOTE, form);
}

result_t syntax_quote(std::istream& in) {
  return pass(do_syntax_quote(read(in)));
}

result_t unquote(std::istream& in) {

  std::string quote =
    (in.peek() == '@') ? (in.get(), "unquote-splicing") : "unquote";

  values_t forms({
    sym_t::intern(quote),
    read(in)
  });

  return pass(list_t::from_std(forms));
}

std::string escape(const std::string& s) {

  std::string out;

  auto i = s.begin();
  auto j = i;

  while (i != s.end()) {
    if (*(i++) == '\\') {
      if (i == s.end()) {
        throw std::runtime_error(
          "Incomplete escape sequence at thend of string");
      }
      out.append(j, i-1);
      switch(*i) {
      case '0':  out += '\0'; break;
      case 'n':  out += '\n'; break;
      case 'r':  out += '\r'; break;
      case 't':  out += '\t'; break;
      case '\\': out += '\\'; break;
      default:
        throw std::runtime_error(
          std::string("Unsupported escape sequence: \\") + *i);
      }
      j = ++i;
    }
  }

  out.append(j, i);

  return out;
}

bool is_sym_token(char c) {
  return
    (c != std::char_traits<char>::eof())
    && (!isspace(c))
    && (c != ')') && (c != '}') && (c != ']')
    //&& (macros.find(c) == macros.end())
    ;
}

result_t read_char(std::istream& in) {
  std::string buf;

  auto ch = in.get();
  while (in.good() && is_sym_token(ch)) {
    buf += ch;
    ch = in.get();
  }

  if (buf.size() == 1) {
    return pass(imu::nu<int_t>(buf[0]));
  }
  else {
    // TODO: interpret char token
  }

  return fail();
}

macro_t string_reader(const ctor_t& ctor) {
  return [=](std::istream& in) {
    std::string str;
    std::getline(in, str, '\"');

    if (in.eof()) {
      throw unbalanced('\"');
    }

    return pass(ctor(escape(str)));
  };
}

result_t read_string(std::istream& in) {
  static const auto read = string_reader([](const std::string& s) {
      return string_t::intern(s);
  });
  return read(in);
}

result_t try_macros(std::istream& in, const macros_t& macs) {

  result_t res = fail();

  auto iter = macs.find(in.peek());
  if (iter != macs.end()) {
    in.get();
    res = iter->second(in);
  }

  return res;
}

result_t unbalanced_error(std::istream& in) {
  throw unbalanced(in.peek());
}

result_t consult_table(std::istream& in) {
  return try_macros(in, extensions);
}

result_t try_default_macros(std::istream& in) {
  return try_macros(in, macros);
}

macro_t symbol_reader(const ctor_t& ctor) {
  return [=](std::istream& in){
    char c = in.peek();
    if (is_sym_token(c)) {

      std::string sym;

      do {

        sym += in.get();
        c = in.peek();

      } while(is_sym_token(c));

      return pass(ctor(sym));
    }

    return fail();
  };
}

result_t read_symbol(std::istream& in) {
  static const auto read = symbol_reader([](const std::string& s){
      if (s == "nil") {
        return sym_t::p();
      }
      return sym_t::intern(s);
    });
  return read(in);
}

result_t read_keyword(std::istream& in) {
  static const auto read = symbol_reader([](const std::string& s){
      if (s.size() > 0 && s[0] == ':') {
        return keyw_t::intern(ns()->name() + "/"  + s.substr(1));
      }
      return keyw_t::intern(s);
    });
  return read(in);
}

result_t try_number(std::istream& in) {

  std::string s;

  if (!isdigit(in.peek())) {
    if (in.peek() == '-') {
      s += in.get();
      if (!isdigit(in.peek())) {
        in.putback('-');
        return fail();
      }
    }
    else {
      return fail();
    }
  }

  do {
    s += in.get();
  } while (isalnum(in.peek()));

  return pass(imu::nu<int_t>(std::stoll(s, nullptr, 0)));
}

void skip_white_space(std::istream& in) {

  char c = in.peek();
  while(isspace(c)) {

    in.get();
    c = in.peek();
  }
}

void skip_comment(std::istream& in) {

  while (in.peek() == ';') {
    do {
      in.get();
    } while (in.peek() != '\n');
    skip_white_space(in);
  }
}

result_t read_or_skip(std::istream& in) {

  skip_white_space(in);
  skip_comment(in);

  if (in.eof()) {
    return pass(nullptr);
  }

  passes_t passes({
      &try_number
    , &try_default_macros
    , &read_symbol});

  result_t res = fail();

  for(auto x : passes) {
    res = x(in);
    if(std::get<0>(res) != parse_state_t::fail) {
      break;
    }
  }

  if (std::get<0>(res) == parse_state_t::fail) {
    throw std::runtime_error("Unable to parse form");
  }

  return res;
}

value_t::p rev::rdr::read(std::istream& in) {
  auto result = read_or_skip(in);
  if (std::get<0>(result) == parse_state_t::pass) {
    return std::get<1>(result);
  }
  return nullptr;
}

value_t::p rev::rdr::read(const std::string& s) {
  std::stringstream in(s);
  return read(in);
}

void set_macro(char begin, const macro_t& reader) {
  macros[begin] = [=](std::istream& in) {
    return reader(in);
  };
}

void push_macro_table(char begin, const macro_t& reader) {
  extensions[begin] = reader;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: tbxctl.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: kz $ $Date: 2005-03-01 19:19:12 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _BASIDE_TBXCTL_HXX
#define _BASIDE_TBXCTL_HXX

#ifndef _SFXTBXCTRL_HXX //autogen
#include <sfx2/tbxctrl.hxx>
#endif

#ifndef _COM_SUN_STAR_FRAME_XLAYOUTMANAGER_HPP_
#include <com/sun/star/frame/XLayoutManager.hpp>
#endif

/*
#ifdef _BASIDE_POPUPWINDOWTBX

// class PopupWindowTbx --------------------------------------------------

class PopupWindowTbx : public SfxPopupWindow
{
private:
    SfxToolBoxManager   aTbx;
    Link                aSelectLink;

    DECL_LINK( SelectHdl, void* );

public:
    PopupWindowTbx( USHORT nId, WindowAlign eAlign,
                    ResId aRIdWin, ResId aRIdTbx, SfxBindings& rBind );
    ~PopupWindowTbx();

    void                    StartSelection()
                                { aTbx.GetToolBox().StartSelection(); }
    void                    Update();

    virtual SfxPopupWindow* Clone() const;
    virtual void            PopupModeEnd();
};
#endif
*/
//-------------------
// class TbxControls
//-------------------
class TbxControls : public SfxToolBoxControl
{
private:

    struct StateChangedInfo
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::frame::XLayoutManager > xLayoutManager;
        bool bDisabled;
    };

    USHORT                  nLastSlot;

    DECL_STATIC_LINK( TbxControls, StateChangedHdl_Impl, StateChangedInfo* );

protected:
    virtual void            StateChanged( USHORT nSID, SfxItemState eState,
                                          const SfxPoolItem* pState );
public:
    SFX_DECL_TOOLBOX_CONTROL();

    TbxControls(USHORT nSlotId, USHORT nId, ToolBox& rTbx );
    ~TbxControls() {}

    virtual SfxPopupWindowType  GetPopupWindowType() const;
    virtual SfxPopupWindow*     CreatePopupWindow();

    void                        Select( USHORT nModifier );
};

#endif // _BASIDE_TBXCTL_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.6.60); FILE MERGED 2005/09/05 13:55:49 rt 1.6.60.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: tbxctl.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 20:11:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _BASIDE_TBXCTL_HXX
#define _BASIDE_TBXCTL_HXX

#ifndef _SFXTBXCTRL_HXX //autogen
#include <sfx2/tbxctrl.hxx>
#endif

#ifndef _COM_SUN_STAR_FRAME_XLAYOUTMANAGER_HPP_
#include <com/sun/star/frame/XLayoutManager.hpp>
#endif

/*
#ifdef _BASIDE_POPUPWINDOWTBX

// class PopupWindowTbx --------------------------------------------------

class PopupWindowTbx : public SfxPopupWindow
{
private:
    SfxToolBoxManager   aTbx;
    Link                aSelectLink;

    DECL_LINK( SelectHdl, void* );

public:
    PopupWindowTbx( USHORT nId, WindowAlign eAlign,
                    ResId aRIdWin, ResId aRIdTbx, SfxBindings& rBind );
    ~PopupWindowTbx();

    void                    StartSelection()
                                { aTbx.GetToolBox().StartSelection(); }
    void                    Update();

    virtual SfxPopupWindow* Clone() const;
    virtual void            PopupModeEnd();
};
#endif
*/
//-------------------
// class TbxControls
//-------------------
class TbxControls : public SfxToolBoxControl
{
private:

    struct StateChangedInfo
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::frame::XLayoutManager > xLayoutManager;
        bool bDisabled;
    };

    USHORT                  nLastSlot;

    DECL_STATIC_LINK( TbxControls, StateChangedHdl_Impl, StateChangedInfo* );

protected:
    virtual void            StateChanged( USHORT nSID, SfxItemState eState,
                                          const SfxPoolItem* pState );
public:
    SFX_DECL_TOOLBOX_CONTROL();

    TbxControls(USHORT nSlotId, USHORT nId, ToolBox& rTbx );
    ~TbxControls() {}

    virtual SfxPopupWindowType  GetPopupWindowType() const;
    virtual SfxPopupWindow*     CreatePopupWindow();

    void                        Select( USHORT nModifier );
};

#endif // _BASIDE_TBXCTL_HXX

<|endoftext|>


<commit_before>/* This file is part of Mapnik (c++ mapping toolkit)
 * Copyright (C) 2005 Artem Pavlenko
 *
 * Mapnik 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
 * of the License, or 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//$Id: render.cpp 44 2005-04-22 18:53:54Z pavlenko $

#include "render.hpp"
#include "line_aa.hpp"
#include "scanline.hpp"
#include "scanline_aa.hpp"
#include "text.hpp"
#include "image_util.hpp"
#include "utils.hpp"
#include "style_cache.hpp"
#include "image_reader.hpp"
#include "polygon_symbolizer.hpp"
#include "line_symbolizer.hpp"
#include "query.hpp"
#include "feature_layer_desc.hpp"
#include "attribute_collector.hpp"
#include "property_index.hpp"

#include <algorithm>
#include <cmath>
#include <set>

namespace mapnik
{

    template <typename Image>
    void Renderer<Image>::render_vector_layer(datasource_p const& ds,
					      std::vector<std::string> const& namedStyles,
					      unsigned width,unsigned height,
					      const Envelope<double>& bbox,Image& image)
    {
	CoordTransform t(width,height,bbox);
	std::vector<std::string>::const_iterator stylesIter=namedStyles.begin();
	while (stylesIter!=namedStyles.end())
	{
	    feature_type_style style=named_style_cache::instance()->find(*stylesIter++);

	    std::set<std::string> names;
	    attribute_collector<Feature> collector(names);
	    property_index<Feature> indexer(names);

	    query q(bbox,width,height);
	    double scale = 1.0/t.scale();
	    std::vector<rule_type*> if_rules;
	    std::vector<rule_type*> else_rules;

	    bool active_rules=false;
	    const std::vector<rule_type>& rules=style.get_rules();
	    std::vector<rule_type>::const_iterator ruleIter=rules.begin();

	    while (ruleIter!=rules.end())
	    {
		if (ruleIter->active(scale))
		{
		    active_rules=true;
		    filter_ptr& filter=const_cast<filter_ptr&>(ruleIter->get_filter());
		    filter->accept(collector);
		    filter->accept(indexer);
		    if (ruleIter->has_else_filter())
		    {
			else_rules.push_back(const_cast<rule_type*>(&(*ruleIter)));
		    }
		    else
		    {
			if_rules.push_back(const_cast<rule_type*>(&(*ruleIter)));
		    }
		}
		++ruleIter;
	    }

	    std::set<std::string>::const_iterator namesIter=names.begin();
	    // push all property names
	    while (namesIter!=names.end())
	    {
		q.add_property_name(*namesIter);
		++namesIter;
	    }
	    //only query datasource if there are active rules
	    if (active_rules)
	    {
		featureset_ptr fs=ds->features(q);
		if (fs)
		{
		    feature_ptr feature;
		    while ((feature = fs->next()))
		    {
			bool do_else=true;
			geometry_ptr& geom=feature->get_geometry();
			if (geom)
			{
			    geom->transform(t);//todo: transform once

			    std::vector<rule_type*>::const_iterator itr=if_rules.begin();
			    while (itr!=if_rules.end())
			    {
				const filter_ptr& filter=(*itr)->get_filter();
				if (filter->pass(*feature))
				{
				    do_else=false;
				    const symbolizers& symbols = (*itr)->get_symbolizers();
				    symbolizers::const_iterator symIter=symbols.begin();
				    while (symIter!=symbols.end())
				    {
					(*symIter)->render(*geom,image);
					++symIter;
				    }
				    break;// not sure !!
				}
				++itr;
			    }
			    if (do_else)
			    {
				//else filter
				std::vector<rule_type*>::const_iterator itr=else_rules.begin();
				while (itr != else_rules.end())
				{
				    const symbolizers& symbols = (*itr)->get_symbolizers();
				    symbolizers::const_iterator symIter=symbols.begin();
				    while (symIter!=symbols.end())
				    {
					(*symIter)->render(*geom,image);
					++symIter;
				    }
				    ++itr;
				}
			    }
			}
		    }
		}

		//if (l.isSelectable() && l.selection().size()) //TODO !!!
		//{
		  //volatile style_cache* styles=style_cache::instance();
		  //  const Style& style=style_cache::instance()->find(l.selection_style());

		//	    std::vector<ref_ptr<Feature> >& selection=l.selection();

		//	    Style::Iterator pos = style.begin();
		//   if (pos!=style.end()) {
		//	std::vector<ref_ptr<Feature> >::iterator itr=selection.begin();
		//
		//	while (itr!=selection.end())
		//	{
		//	    geometry_ptr& geom=(*itr)->get_geometry();
		//	    geom->transform(t);
		//	    (*pos)->render(*geom,image);
		//	    ++itr;
		//	}
		//   }
		//    l.clear_selection();
		//}
	    }
	}
    }

    template <typename Image>
    void Renderer<Image>::render_raster_layer(datasource_p const& ds,
					      std::vector<std::string> const& ,
					      unsigned width,unsigned height,
					      const Envelope<double>& bbox,Image& image)
    {
	query q(bbox,width,height);
	featureset_ptr fs=ds->features(q);
	if (fs)
	{
	    feature_ptr feature;
	    while ((feature = fs->next()))
	    {
		raster_ptr const& raster=feature->get_raster();
		if (raster)
		{
		    image.set_rectangle(raster->x_,raster->y_,raster->data_);
		}
	    }
	}
    }

    template <typename Image>
    void Renderer<Image>::render(const Map& map,Image& image)
    {
        timer clock;
        //////////////////////////////////////////////////////
        const Envelope<double>& extent=map.getCurrentExtent();
	std::cout<<"BBOX:"<<extent<<std::endl;
        double scale=map.scale();
        std::cout<<" scale="<<scale<<std::endl;

	unsigned width=map.getWidth();
        unsigned height=map.getHeight();

        Color const& background=map.getBackground();
        image.setBackground(background);

        for (size_t n=0;n<map.layerCount();++n)
        {
            const Layer& l=map.getLayer(n);
            if (l.isVisible(scale)) // TODO: extent check
	    {
		const datasource_p& ds=l.datasource();
		if (!ds) continue;
                if (ds->type() == datasource::Vector)
		{
		    render_vector_layer(ds,l.styles(),width,height,extent,image);
		}
		else if (ds->type() == datasource::Raster)
		{
		    render_raster_layer(ds,l.styles(),width,height,extent,image);
		}
            }
        }
        clock.stop();
    }

    template class Renderer<Image32>;
}
<commit_msg>removed erroneous break statement (was added to render OS MasterMap)<commit_after>/* This file is part of Mapnik (c++ mapping toolkit)
 * Copyright (C) 2005 Artem Pavlenko
 *
 * Mapnik 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
 * of the License, or 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//$Id: render.cpp 44 2005-04-22 18:53:54Z pavlenko $

#include "render.hpp"
#include "line_aa.hpp"
#include "scanline.hpp"
#include "scanline_aa.hpp"
#include "text.hpp"
#include "image_util.hpp"
#include "utils.hpp"
#include "style_cache.hpp"
#include "image_reader.hpp"
#include "polygon_symbolizer.hpp"
#include "line_symbolizer.hpp"
#include "query.hpp"
#include "feature_layer_desc.hpp"
#include "attribute_collector.hpp"
#include "property_index.hpp"

#include <algorithm>
#include <cmath>
#include <set>

namespace mapnik
{

    template <typename Image>
    void Renderer<Image>::render_vector_layer(datasource_p const& ds,
					      std::vector<std::string> const& namedStyles,
					      unsigned width,unsigned height,
					      const Envelope<double>& bbox,Image& image)
    {
	CoordTransform t(width,height,bbox);
	std::vector<std::string>::const_iterator stylesIter=namedStyles.begin();
	while (stylesIter!=namedStyles.end())
	{
	    feature_type_style style=named_style_cache::instance()->find(*stylesIter++);

	    std::set<std::string> names;
	    attribute_collector<Feature> collector(names);
	    property_index<Feature> indexer(names);

	    query q(bbox,width,height);
	    double scale = 1.0/t.scale();
	    std::vector<rule_type*> if_rules;
	    std::vector<rule_type*> else_rules;

	    bool active_rules=false;
	    const std::vector<rule_type>& rules=style.get_rules();
	    std::vector<rule_type>::const_iterator ruleIter=rules.begin();

	    while (ruleIter!=rules.end())
	    {
		if (ruleIter->active(scale))
		{
		    active_rules=true;
		    filter_ptr& filter=const_cast<filter_ptr&>(ruleIter->get_filter());
		    filter->accept(collector);
		    filter->accept(indexer);
		    if (ruleIter->has_else_filter())
		    {
			else_rules.push_back(const_cast<rule_type*>(&(*ruleIter)));
		    }
		    else
		    {
			if_rules.push_back(const_cast<rule_type*>(&(*ruleIter)));
		    }
		}
		++ruleIter;
	    }

	    std::set<std::string>::const_iterator namesIter=names.begin();
	    // push all property names
	    while (namesIter!=names.end())
	    {
		q.add_property_name(*namesIter);
		++namesIter;
	    }
	    //only query datasource if there are active rules
	    if (active_rules)
	    {
		featureset_ptr fs=ds->features(q);
		if (fs)
		{
		    feature_ptr feature;
		    while ((feature = fs->next()))
		    {
			bool do_else=true;
			geometry_ptr& geom=feature->get_geometry();
			if (geom)
			{
			    geom->transform(t);//todo: transform once

			    std::vector<rule_type*>::const_iterator itr=if_rules.begin();
			    while (itr!=if_rules.end())
			    {
				const filter_ptr& filter=(*itr)->get_filter();
				if (filter->pass(*feature))
				{
				    do_else=false;
				    const symbolizers& symbols = (*itr)->get_symbolizers();
				    symbolizers::const_iterator symIter=symbols.begin();
				    while (symIter!=symbols.end())
				    {
					(*symIter)->render(*geom,image);
					++symIter;
				    }
				}
				++itr;
			    }
			    if (do_else)
			    {
				//else filter
				std::vector<rule_type*>::const_iterator itr=else_rules.begin();
				while (itr != else_rules.end())
				{
				    const symbolizers& symbols = (*itr)->get_symbolizers();
				    symbolizers::const_iterator symIter=symbols.begin();
				    while (symIter!=symbols.end())
				    {
					(*symIter)->render(*geom,image);
					++symIter;
				    }
				    ++itr;
				}
			    }
			}
		    }
		}

		//if (l.isSelectable() && l.selection().size()) //TODO !!!
		//{
		  //volatile style_cache* styles=style_cache::instance();
		  //  const Style& style=style_cache::instance()->find(l.selection_style());

		//	    std::vector<ref_ptr<Feature> >& selection=l.selection();

		//	    Style::Iterator pos = style.begin();
		//   if (pos!=style.end()) {
		//	std::vector<ref_ptr<Feature> >::iterator itr=selection.begin();
		//
		//	while (itr!=selection.end())
		//	{
		//	    geometry_ptr& geom=(*itr)->get_geometry();
		//	    geom->transform(t);
		//	    (*pos)->render(*geom,image);
		//	    ++itr;
		//	}
		//   }
		//    l.clear_selection();
		//}
	    }
	}
    }

    template <typename Image>
    void Renderer<Image>::render_raster_layer(datasource_p const& ds,
					      std::vector<std::string> const& ,
					      unsigned width,unsigned height,
					      const Envelope<double>& bbox,Image& image)
    {
	query q(bbox,width,height);
	featureset_ptr fs=ds->features(q);
	if (fs)
	{
	    feature_ptr feature;
	    while ((feature = fs->next()))
	    {
		raster_ptr const& raster=feature->get_raster();
		if (raster)
		{
		    image.set_rectangle(raster->x_,raster->y_,raster->data_);
		}
	    }
	}
    }

    template <typename Image>
    void Renderer<Image>::render(const Map& map,Image& image)
    {
        timer clock;
        //////////////////////////////////////////////////////
        const Envelope<double>& extent=map.getCurrentExtent();
	std::cout<<"BBOX:"<<extent<<std::endl;
        double scale=map.scale();
        std::cout<<" scale="<<scale<<std::endl;

	unsigned width=map.getWidth();
        unsigned height=map.getHeight();

        Color const& background=map.getBackground();
        image.setBackground(background);

        for (size_t n=0;n<map.layerCount();++n)
        {
            const Layer& l=map.getLayer(n);
            if (l.isVisible(scale)) // TODO: extent check
	    {
		const datasource_p& ds=l.datasource();
		if (!ds) continue;
                if (ds->type() == datasource::Vector)
		{
		    render_vector_layer(ds,l.styles(),width,height,extent,image);
		}
		else if (ds->type() == datasource::Raster)
		{
		    render_raster_layer(ds,l.styles(),width,height,extent,image);
		}
            }
        }
        clock.stop();
    }

    template class Renderer<Image32>;
}
<|endoftext|>


<commit_before>// schokwaveDeath.cpp : Defines the entry point for the DLL application.
//

#include "bzfsAPI.h"
#include <string>

// event handaler callback
class DeathHandaler : public bz_EventHandaler
{
public:
	virtual void process ( bz_EventData *eventData );
};

DeathHandaler	deathHandaler;

int bz_Load ( const char* commandLine )
{
	bz_registerEvent(bz_ePlayerDieEvent,BZ_ALL_USERS,&deathHandaler);
	return 0;
}

int bz_Unload ( void )
{
	return 0;
}

void DeathHandaler::process ( bz_EventData *eventData )
{
	if (eventData->eventType != bz_ePlayerDieEvent)
		return;

	bz_PlayerDieEventData	*dieData = (bz_PlayerDieEventData*)eventData;

	bz_fireWorldWep("SW",10,BZ_SERVER,dieData->pos,0,0,0,0);
}<commit_msg>grab reload time for lifetime for on death shockwave<commit_after>// schokwaveDeath.cpp : Defines the entry point for the DLL application.
//

#include "bzfsAPI.h"
#include <string>

// event handaler callback
class DeathHandaler : public bz_EventHandaler
{
public:
	virtual void process ( bz_EventData *eventData );
};

DeathHandaler	deathHandaler;

int bz_Load ( const char* commandLine )
{
	bz_registerEvent(bz_ePlayerDieEvent,BZ_ALL_USERS,&deathHandaler);
	return 0;
}

int bz_Unload ( void )
{
	return 0;
}

void DeathHandaler::process ( bz_EventData *eventData )
{
	if (eventData->eventType != bz_ePlayerDieEvent)
		return;

	bz_PlayerDieEventData	*dieData = (bz_PlayerDieEventData*)eventData;

	bz_fireWorldWep("SW",bz_getBZDBDouble("_reloadTime"),BZ_SERVER,dieData->pos,0,0,0,0);
}<|endoftext|>


<commit_before>
// Prefab.cpp

/*
Implements the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
uses a prefabricate in a cBlockArea for drawing itself.
*/

#include "Globals.h"
#include "Prefab.h"
#include "../WorldStorage/SchematicFileSerializer.h"
#include "ChunkDesc.h"

#ifdef SELF_TEST

// Create one static prefab to test the parser:
static const cPrefab::sDef g_TestPrefabDef =
{
	// Size:
	7, 6, 7,  // SizeX = 7, SizeY = 6, SizeZ = 7

	// Block definitions:
	".:  0: 0\n"  /* 0 */
	"a:112: 0\n"  /* netherbrick */
	"b:113: 0\n"  /* netherbrickfence */,

	// Block data:
	// Level 1
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"

	// Level 2
	"aa...aa"
	"a.....a"
	"......."
	"......."
	"......."
	"a.....a"
	"aa...aa"

	// Level 3
	"aa...aa"
	"a.....a"
	"......."
	"......."
	"......."
	"a.....a"
	"aa...aa"

	// Level 4
	"aa...aa"
	"a.....a"
	"......."
	"......."
	"......."
	"a.....a"
	"aa...aa"

	// Level 5
	"aabbbaa"
	"a.....a"
	"b.....b"
	"b.....b"
	"b.....b"
	"a.....a"
	"aabbbaa"

	// Level 6
	"aaaaaaa"
	"a.....a"
	"a.....a"
	"a.....a"
	"a.....a"
	"a.....a"
	"aaaaaaa",

	// Connections:
	"0: 0, 3, 2: 4\n"
	"0: 2, 3, 0: 2\n",

	// AllowedRotations:
	7,  /* 1, 2, 3 CCW rotations */

	// Merge strategy:
	cBlockArea::msImprint
};

static cPrefab g_TestPrefab(g_TestPrefabDef);
#endif

cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
	m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ),
	m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1),
	m_AllowedRotations(a_Def.m_AllowedRotations),
	m_MergeStrategy(a_Def.m_MergeStrategy)
{
	m_BlockArea[0].Create(m_Size);
	CharMap cm;
	ParseCharMap(cm, a_Def.m_CharMap);
	ParseBlockImage(cm, a_Def.m_Image);
	ParseConnectors(a_Def.m_Connectors);

	// 1 CCW rotation:
	if ((m_AllowedRotations & 0x01) != 0)
	{
		m_BlockArea[1].CopyFrom(m_BlockArea[0]);
		m_BlockArea[1].RotateCCW();
	}

	// 2 rotations are the same as mirroring twice; mirroring is faster because it has no reallocations
	if ((m_AllowedRotations & 0x02) != 0)
	{
		m_BlockArea[2].CopyFrom(m_BlockArea[0]);
		m_BlockArea[2].MirrorXY();
		m_BlockArea[2].MirrorYZ();
	}

	// 3 CCW rotations = 1 CW rotation:
	if ((m_AllowedRotations & 0x04) != 0)
	{
		m_BlockArea[3].CopyFrom(m_BlockArea[0]);
		m_BlockArea[3].RotateCW();
	}
}

void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
{
	Vector3i Placement = a_Placement->GetCoords();
	int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width;
	int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
	Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
	a_Dest.WriteBlockArea(m_BlockArea[a_Placement->GetNumCCWRotations()], Placement.x, Placement.y, Placement.z, m_MergeStrategy);

}

bool cPrefab::HasConnectorType(int a_ConnectorType) const
{
	for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
	{
		if (itr->m_Type == a_ConnectorType)
		{
			return true;
		}
	}  // for itr - m_Connectors[]
	return false;
}

void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
{
	// Initialize the charmap to all-invalid values:
	for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++)
	{
		a_CharMapOut[i].m_BlockType = 0;
		a_CharMapOut[i].m_BlockMeta = 16;  // Mark unassigned entries with a meta that is impossible otherwise
	}

	// Process the lines in the definition:
	AStringVector Lines = StringSplitAndTrim(a_CharMapDef, "\n");
	for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
	{
		AStringVector CharDef = StringSplitAndTrim(*itr, ":");
		size_t NumElements = CharDef.size();
		if ((NumElements < 2) || CharDef[0].empty() || CharDef[1].empty())
		{
			LOGWARNING("Bad prefab CharMap definition line: \"%s\", skipping.", itr->c_str());
			continue;
		}
		unsigned char Src = (unsigned char)CharDef[0][0];
		ASSERT(a_CharMapOut[Src].m_BlockMeta == 16);  // This letter has not been assigned yet?
		a_CharMapOut[Src].m_BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str());
		NIBBLETYPE BlockMeta = 0;
		if ((NumElements >= 3) && !CharDef[2].empty())
		{
			BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
			ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
		}
		a_CharMapOut[Src].m_BlockMeta = BlockMeta;
	}  // for itr - Lines[]
}

void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage)
{
	// Map each letter in the a_BlockImage (from the in-source definition) to real blocktype / blockmeta:
	for (int y = 0; y < m_Size.y; y++)
	{
		for (int z = 0; z < m_Size.z; z++)
		{
			const unsigned char * BlockImage = (const unsigned char *)a_BlockImage + y * m_Size.x * m_Size.z + z * m_Size.x;
			for (int x = 0; x < m_Size.x; x++)
			{
				const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]];
				ASSERT(MappedValue.m_BlockMeta != 16);  // Using a letter not defined in the CharMap?
				m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta);
			}
		}
	}
}

void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
{
	AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n");
	for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
	{
		if (itr->empty())
		{
			continue;
		}
		// Split into components: "Type: X, Y, Z: Face":
		AStringVector Defs = StringSplitAndTrim(*itr, ":");
		if (Defs.size() != 3)
		{
			LOGWARNING("Bad prefab Connector definition line: \"%s\", skipping.", itr->c_str());
			continue;
		}
		AStringVector Coords = StringSplitAndTrim(Defs[1], ",");
		if (Coords.size() != 3)
		{
			LOGWARNING("Bad prefab Connector coords definition: \"%s\", skipping.", Defs[1].c_str());
			continue;
		}

		// Check that the BlockFace is within range:
		int BlockFace = atoi(Defs[2].c_str());
		if ((BlockFace < 0) || (BlockFace >= 6))
		{
			LOGWARNING("Bad prefab Connector Blockface: \"%s\", skipping.", Defs[2].c_str());
			continue;
		}

		// Add the connector:
		m_Connectors.push_back(cPiece::cConnector(
			atoi(Coords[0].c_str()), atoi(Coords[1].c_str()), atoi(Coords[2].c_str()),  // Connector pos
			atoi(Defs[0].c_str()),  // Connector type
			(eBlockFace)BlockFace
		));
	}  // for itr - Lines[]
}

cPiece::cConnectors cPrefab::GetConnectors(void) const
{
	return m_Connectors;
}

Vector3i cPrefab::GetSize(void) const
{
	return m_Size;
}

cCuboid cPrefab::GetHitBox(void) const
{
	return m_HitBox;
}

bool cPrefab::CanRotateCCW(int a_NumRotations) const
{
	// Either zero rotations
	// Or the proper bit in m_AllowedRotations is set
	return (a_NumRotations == 0) || ((m_AllowedRotations & (1 << ((a_NumRotations + 3) % 4))) != 0);
}

<commit_msg>Added asserts for critical data in cPrefab.<commit_after>
// Prefab.cpp

/*
Implements the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
uses a prefabricate in a cBlockArea for drawing itself.
*/

#include "Globals.h"
#include "Prefab.h"
#include "../WorldStorage/SchematicFileSerializer.h"
#include "ChunkDesc.h"

#ifdef SELF_TEST

// Create one static prefab to test the parser:
static const cPrefab::sDef g_TestPrefabDef =
{
	// Size:
	7, 6, 7,  // SizeX = 7, SizeY = 6, SizeZ = 7

	// Block definitions:
	".:  0: 0\n"  /* 0 */
	"a:112: 0\n"  /* netherbrick */
	"b:113: 0\n"  /* netherbrickfence */,

	// Block data:
	// Level 1
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"
	"aaaaaaa"

	// Level 2
	"aa...aa"
	"a.....a"
	"......."
	"......."
	"......."
	"a.....a"
	"aa...aa"

	// Level 3
	"aa...aa"
	"a.....a"
	"......."
	"......."
	"......."
	"a.....a"
	"aa...aa"

	// Level 4
	"aa...aa"
	"a.....a"
	"......."
	"......."
	"......."
	"a.....a"
	"aa...aa"

	// Level 5
	"aabbbaa"
	"a.....a"
	"b.....b"
	"b.....b"
	"b.....b"
	"a.....a"
	"aabbbaa"

	// Level 6
	"aaaaaaa"
	"a.....a"
	"a.....a"
	"a.....a"
	"a.....a"
	"a.....a"
	"aaaaaaa",

	// Connections:
	"0: 0, 3, 2: 4\n"
	"0: 2, 3, 0: 2\n",

	// AllowedRotations:
	7,  /* 1, 2, 3 CCW rotations */

	// Merge strategy:
	cBlockArea::msImprint
};

static cPrefab g_TestPrefab(g_TestPrefabDef);
#endif

cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
	m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ),
	m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1),
	m_AllowedRotations(a_Def.m_AllowedRotations),
	m_MergeStrategy(a_Def.m_MergeStrategy)
{
	m_BlockArea[0].Create(m_Size);
	CharMap cm;
	ParseCharMap(cm, a_Def.m_CharMap);
	ParseBlockImage(cm, a_Def.m_Image);
	ParseConnectors(a_Def.m_Connectors);

	// 1 CCW rotation:
	if ((m_AllowedRotations & 0x01) != 0)
	{
		m_BlockArea[1].CopyFrom(m_BlockArea[0]);
		m_BlockArea[1].RotateCCW();
	}

	// 2 rotations are the same as mirroring twice; mirroring is faster because it has no reallocations
	if ((m_AllowedRotations & 0x02) != 0)
	{
		m_BlockArea[2].CopyFrom(m_BlockArea[0]);
		m_BlockArea[2].MirrorXY();
		m_BlockArea[2].MirrorYZ();
	}

	// 3 CCW rotations = 1 CW rotation:
	if ((m_AllowedRotations & 0x04) != 0)
	{
		m_BlockArea[3].CopyFrom(m_BlockArea[0]);
		m_BlockArea[3].RotateCW();
	}
}

void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
{
	Vector3i Placement = a_Placement->GetCoords();
	int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width;
	int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
	Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
	a_Dest.WriteBlockArea(m_BlockArea[a_Placement->GetNumCCWRotations()], Placement.x, Placement.y, Placement.z, m_MergeStrategy);

}

bool cPrefab::HasConnectorType(int a_ConnectorType) const
{
	for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
	{
		if (itr->m_Type == a_ConnectorType)
		{
			return true;
		}
	}  // for itr - m_Connectors[]
	return false;
}

void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
{
	ASSERT(a_CharMapDef != NULL);

	// Initialize the charmap to all-invalid values:
	for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++)
	{
		a_CharMapOut[i].m_BlockType = 0;
		a_CharMapOut[i].m_BlockMeta = 16;  // Mark unassigned entries with a meta that is impossible otherwise
	}

	// Process the lines in the definition:
	AStringVector Lines = StringSplitAndTrim(a_CharMapDef, "\n");
	for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
	{
		AStringVector CharDef = StringSplitAndTrim(*itr, ":");
		size_t NumElements = CharDef.size();
		if ((NumElements < 2) || CharDef[0].empty() || CharDef[1].empty())
		{
			LOGWARNING("Bad prefab CharMap definition line: \"%s\", skipping.", itr->c_str());
			continue;
		}
		unsigned char Src = (unsigned char)CharDef[0][0];
		ASSERT(a_CharMapOut[Src].m_BlockMeta == 16);  // This letter has not been assigned yet?
		a_CharMapOut[Src].m_BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str());
		NIBBLETYPE BlockMeta = 0;
		if ((NumElements >= 3) && !CharDef[2].empty())
		{
			BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
			ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
		}
		a_CharMapOut[Src].m_BlockMeta = BlockMeta;
	}  // for itr - Lines[]
}

void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage)
{
	// Map each letter in the a_BlockImage (from the in-source definition) to real blocktype / blockmeta:
	for (int y = 0; y < m_Size.y; y++)
	{
		for (int z = 0; z < m_Size.z; z++)
		{
			const unsigned char * BlockImage = (const unsigned char *)a_BlockImage + y * m_Size.x * m_Size.z + z * m_Size.x;
			for (int x = 0; x < m_Size.x; x++)
			{
				const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]];
				ASSERT(MappedValue.m_BlockMeta != 16);  // Using a letter not defined in the CharMap?
				m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta);
			}
		}
	}
}

void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
{
	ASSERT(a_ConnectorsDef != NULL);

	AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n");
	for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
	{
		if (itr->empty())
		{
			continue;
		}
		// Split into components: "Type: X, Y, Z: Face":
		AStringVector Defs = StringSplitAndTrim(*itr, ":");
		if (Defs.size() != 3)
		{
			LOGWARNING("Bad prefab Connector definition line: \"%s\", skipping.", itr->c_str());
			continue;
		}
		AStringVector Coords = StringSplitAndTrim(Defs[1], ",");
		if (Coords.size() != 3)
		{
			LOGWARNING("Bad prefab Connector coords definition: \"%s\", skipping.", Defs[1].c_str());
			continue;
		}

		// Check that the BlockFace is within range:
		int BlockFace = atoi(Defs[2].c_str());
		if ((BlockFace < 0) || (BlockFace >= 6))
		{
			LOGWARNING("Bad prefab Connector Blockface: \"%s\", skipping.", Defs[2].c_str());
			continue;
		}

		// Add the connector:
		m_Connectors.push_back(cPiece::cConnector(
			atoi(Coords[0].c_str()), atoi(Coords[1].c_str()), atoi(Coords[2].c_str()),  // Connector pos
			atoi(Defs[0].c_str()),  // Connector type
			(eBlockFace)BlockFace
		));
	}  // for itr - Lines[]
}

cPiece::cConnectors cPrefab::GetConnectors(void) const
{
	return m_Connectors;
}

Vector3i cPrefab::GetSize(void) const
{
	return m_Size;
}

cCuboid cPrefab::GetHitBox(void) const
{
	return m_HitBox;
}

bool cPrefab::CanRotateCCW(int a_NumRotations) const
{
	// Either zero rotations
	// Or the proper bit in m_AllowedRotations is set
	return (a_NumRotations == 0) || ((m_AllowedRotations & (1 << ((a_NumRotations + 3) % 4))) != 0);
}

<|endoftext|>


<commit_before>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/

/* See pamAuthRequest.h for a description of this API call.*/

#include <sys/wait.h>

#include "pamAuthRequest.hpp"
#include "genQuery.hpp"
#include "reGlobalsExtern.hpp"
#include "icatHighLevelRoutines.hpp"
#include "miscServerFunct.hpp"

int
rsPamAuthRequest( rsComm_t *rsComm, pamAuthRequestInp_t *pamAuthRequestInp,
                  pamAuthRequestOut_t **pamAuthRequestOut ) {
    rodsServerHost_t *rodsServerHost;
    int status;

    status = getAndConnRcatHost( rsComm, MASTER_RCAT,
                                 rsComm->clientUser.rodsZone, &rodsServerHost );
    if ( status < 0 ) {
        return( status );
    }
    if ( rodsServerHost->localFlag == LOCAL_HOST ) {
#ifdef RODS_CAT
        status = _rsPamAuthRequest( rsComm,  pamAuthRequestInp,
                                    pamAuthRequestOut );

#else
        status = SYS_NO_RCAT_SERVER_ERR;
#endif
    }
    else {
        /* protect the PAM plain text password by
           using an SSL connection to the remote ICAT */
        status = sslStart( rodsServerHost->conn );
        if ( status ) {
            rodsLog( LOG_NOTICE, "rsPamAuthRequest: could not establish SSL connection, status %d",
                     status );
            return( status );
        }

        status = rcPamAuthRequest( rodsServerHost->conn, pamAuthRequestInp,
                                   pamAuthRequestOut );
        sslEnd( rodsServerHost->conn );
        rcDisconnect( rodsServerHost->conn );
        rodsServerHost->conn = NULL;
        if ( status < 0 ) {
            rodsLog( LOG_NOTICE, "rsPamAuthRequest: rcPamAuthRequest to remote server failed, status %d",
                     status );
        }
    }
    return ( status );
}

#ifdef RODS_CAT
/*
 Fork and exec the PamAuthCheck program, which is setuid root, to do
 do the PAM authentication.  The username is on the command line but
 the password is sent on a pipe to be more secure.
 */
#ifndef PAM_AUTH_CHECK_PROG
#define PAM_AUTH_CHECK_PROG  "./PamAuthCheck"
#endif
int
runPamAuthCheck( char *username, char *password ) {
    int p2cp[2]; /* parent to child pipe */
    int pid, i;
    int status;

    if ( pipe( p2cp ) < 0 ) {
        return( SYS_PIPE_ERROR );
    }
    pid = fork();
    if ( pid == -1 ) {
        return( SYS_FORK_ERROR );
    }

    if ( pid )  {
        /*
          This is still the parent.  Write the message to the child and
          then wait for the exit and status.
        */
        write( p2cp[1], password, strlen( password ) );
        close( p2cp[1] );
        waitpid( pid, &status, 0 );
        return( status );
    }
    else {
        /* This is the child */
        close( 0 );        /* close current stdin */
        dup( p2cp[0] );    /* Make stdin come from read end of the pipe */
        close( p2cp[1] );
        i = execl( PAM_AUTH_CHECK_PROG, PAM_AUTH_CHECK_PROG, username,
                   ( char * )NULL );
        perror( "execl" );
        printf( "execl failed %d\n", i );
    }
    return( SYS_FORK_ERROR ); /* avoid compiler warning */
}

int
_rsPamAuthRequest( rsComm_t *rsComm, pamAuthRequestInp_t *pamAuthRequestInp,
                   pamAuthRequestOut_t **pamAuthRequestOut ) {
    int status = 0;
    pamAuthRequestOut_t *result;

    *pamAuthRequestOut = ( pamAuthRequestOut_t * )
                         malloc( sizeof( pamAuthRequestOut_t ) );
    memset( ( char * )*pamAuthRequestOut, 0, sizeof( pamAuthRequestOut_t ) );

    result = *pamAuthRequestOut;

#if defined(PAM_AUTH)

#ifdef RUN_SERVER_AS_ROOT
    /* uid == euid is needed for some plugins e.g. libpam-sss */
    status = changeToRootUser();
    if ( status < 0 ) {
        return ( status );
    }
#endif
    /* Normal mode, fork/exec setuid program to do the Pam check */
    status = runPamAuthCheck( pamAuthRequestInp->pamUser,
                              pamAuthRequestInp->pamPassword );
#ifdef RUN_SERVER_AS_ROOT
    changeToServiceUser();
#endif
    if ( status == 256 ) {
        status = PAM_AUTH_PASSWORD_FAILED;
    }
    else {
        /* the exec failed or something (PamAuthCheck not built perhaps) */
        if ( status != 0 ) {
            status = PAM_AUTH_NOT_BUILT_INTO_SERVER;
        }
    }

    if ( status ) {
        return( status );
    }
    result->irodsPamPassword = ( char* )malloc( 100 );
    if ( result->irodsPamPassword == 0 ) {
        return ( SYS_MALLOC_ERR );
    }
    status = chlUpdateIrodsPamPassword( rsComm,
                                        pamAuthRequestInp->pamUser,
                                        pamAuthRequestInp->timeToLive,
                                        NULL,
                                        &result->irodsPamPassword );
    return( status );
#else
    status = PAM_AUTH_NOT_BUILT_INTO_SERVER;
    return ( status );
#endif
}
#endif /* RODS_CAT */
<commit_msg>[#1880] fixed run as root code in rsPamAuthRequest.cpp<commit_after>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/

/* See pamAuthRequest.h for a description of this API call.*/

#include <sys/wait.h>

#include "pamAuthRequest.hpp"
#include "genQuery.hpp"
#include "reGlobalsExtern.hpp"
#include "icatHighLevelRoutines.hpp"
#include "miscServerFunct.hpp"
#include "irods_server_properties.hpp"
#include "readServerConfig.hpp"

int
rsPamAuthRequest( rsComm_t *rsComm, pamAuthRequestInp_t *pamAuthRequestInp,
                  pamAuthRequestOut_t **pamAuthRequestOut ) {
    rodsServerHost_t *rodsServerHost;
    int status;

    status = getAndConnRcatHost( rsComm, MASTER_RCAT,
                                 rsComm->clientUser.rodsZone, &rodsServerHost );
    if ( status < 0 ) {
        return( status );
    }
    if ( rodsServerHost->localFlag == LOCAL_HOST ) {
#ifdef RODS_CAT
        status = _rsPamAuthRequest( rsComm,  pamAuthRequestInp,
                                    pamAuthRequestOut );

#else
        status = SYS_NO_RCAT_SERVER_ERR;
#endif
    }
    else {
        /* protect the PAM plain text password by
           using an SSL connection to the remote ICAT */
        status = sslStart( rodsServerHost->conn );
        if ( status ) {
            rodsLog( LOG_NOTICE, "rsPamAuthRequest: could not establish SSL connection, status %d",
                     status );
            return( status );
        }

        status = rcPamAuthRequest( rodsServerHost->conn, pamAuthRequestInp,
                                   pamAuthRequestOut );
        sslEnd( rodsServerHost->conn );
        rcDisconnect( rodsServerHost->conn );
        rodsServerHost->conn = NULL;
        if ( status < 0 ) {
            rodsLog( LOG_NOTICE, "rsPamAuthRequest: rcPamAuthRequest to remote server failed, status %d",
                     status );
        }
    }
    return ( status );
}

#ifdef RODS_CAT
/*
 Fork and exec the PamAuthCheck program, which is setuid root, to do
 do the PAM authentication.  The username is on the command line but
 the password is sent on a pipe to be more secure.
 */
#ifndef PAM_AUTH_CHECK_PROG
#define PAM_AUTH_CHECK_PROG  "./PamAuthCheck"
#endif
int
runPamAuthCheck( char *username, char *password ) {
    int p2cp[2]; /* parent to child pipe */
    int pid, i;
    int status;

    if ( pipe( p2cp ) < 0 ) {
        return( SYS_PIPE_ERROR );
    }
    pid = fork();
    if ( pid == -1 ) {
        return( SYS_FORK_ERROR );
    }

    if ( pid )  {
        /*
          This is still the parent.  Write the message to the child and
          then wait for the exit and status.
        */
        write( p2cp[1], password, strlen( password ) );
        close( p2cp[1] );
        waitpid( pid, &status, 0 );
        return( status );
    }
    else {
        /* This is the child */
        close( 0 );        /* close current stdin */
        dup( p2cp[0] );    /* Make stdin come from read end of the pipe */
        close( p2cp[1] );
        i = execl( PAM_AUTH_CHECK_PROG, PAM_AUTH_CHECK_PROG, username,
                   ( char * )NULL );
        perror( "execl" );
        printf( "execl failed %d\n", i );
    }
    return( SYS_FORK_ERROR ); /* avoid compiler warning */
}

int
_rsPamAuthRequest( rsComm_t *rsComm, pamAuthRequestInp_t *pamAuthRequestInp,
                   pamAuthRequestOut_t **pamAuthRequestOut ) {
    int status = 0;
    pamAuthRequestOut_t *result;
    bool run_server_as_root = false;

    *pamAuthRequestOut = ( pamAuthRequestOut_t * )
                         malloc( sizeof( pamAuthRequestOut_t ) );
    memset( ( char * )*pamAuthRequestOut, 0, sizeof( pamAuthRequestOut_t ) );

    result = *pamAuthRequestOut;

#if defined(PAM_AUTH)

    irods::server_properties::getInstance().get_property<bool>(RUN_SERVER_AS_ROOT_KW, run_server_as_root);

    if (run_server_as_root) {
		/* uid == euid is needed for some plugins e.g. libpam-sss */
		status = changeToRootUser();
		if ( status < 0 ) {
			return ( status );
		}
    }
    /* Normal mode, fork/exec setuid program to do the Pam check */
    status = runPamAuthCheck( pamAuthRequestInp->pamUser,
                              pamAuthRequestInp->pamPassword );
    if (run_server_as_root) {
    	changeToServiceUser();
    }
    if ( status == 256 ) {
        status = PAM_AUTH_PASSWORD_FAILED;
    }
    else {
        /* the exec failed or something (PamAuthCheck not built perhaps) */
        if ( status != 0 ) {
            status = PAM_AUTH_NOT_BUILT_INTO_SERVER;
        }
    }

    if ( status ) {
        return( status );
    }
    result->irodsPamPassword = ( char* )malloc( 100 );
    if ( result->irodsPamPassword == 0 ) {
        return ( SYS_MALLOC_ERR );
    }
    status = chlUpdateIrodsPamPassword( rsComm,
                                        pamAuthRequestInp->pamUser,
                                        pamAuthRequestInp->timeToLive,
                                        NULL,
                                        &result->irodsPamPassword );
    return( status );
#else
    status = PAM_AUTH_NOT_BUILT_INTO_SERVER;
    return ( status );
#endif
}
#endif /* RODS_CAT */
<|endoftext|>


<commit_before>#include "drakeJointUtil.h"
#include "makeUnique.h"
#include "DrakeJoint.h"
#include "HelicalJoint.h"
#include "PrismaticJoint.h"
#include "RevoluteJoint.h"
#include "QuaternionFloatingJoint.h"
#include "RollPitchYawFloatingJoint.h"
#include <cmath>

using namespace Eigen;

std::unique_ptr<DrakeJoint> createJoint(const std::string& joint_name, const Isometry3d& transform_to_parent_body, int floating, const Vector3d& joint_axis, double pitch)
{
  std::unique_ptr<DrakeJoint> joint;
  switch (floating) {
  case 0: {
    if (pitch == 0.0) {
      joint = std::make_unique<RevoluteJoint>(joint_name, transform_to_parent_body, joint_axis);
    } else if (std::isinf(pitch)) {
      joint = std::make_unique<PrismaticJoint>(joint_name, transform_to_parent_body, joint_axis);
    } else {
      joint = std::make_unique<HelicalJoint>(joint_name, transform_to_parent_body, joint_axis, pitch);
    }
    break;
  }
  case 1: {
    joint = std::make_unique<RollPitchYawFloatingJoint>(joint_name, transform_to_parent_body);
    break;
  }
  case 2: {
    joint = std::make_unique<QuaternionFloatingJoint>(joint_name, transform_to_parent_body);
    break;
  }
  default: {
    std::ostringstream stream;
    stream << "floating type " << floating << " not recognized.";
    throw std::runtime_error(stream.str());
    break;
  }
  }
  return joint;
}
<commit_msg>Added missing stdexcept include.<commit_after>#include "drakeJointUtil.h"
#include "makeUnique.h"
#include "DrakeJoint.h"
#include "HelicalJoint.h"
#include "PrismaticJoint.h"
#include "RevoluteJoint.h"
#include "QuaternionFloatingJoint.h"
#include "RollPitchYawFloatingJoint.h"
#include <cmath>
#include <stdexcept>

using namespace Eigen;

std::unique_ptr<DrakeJoint> createJoint(const std::string& joint_name, const Isometry3d& transform_to_parent_body, int floating, const Vector3d& joint_axis, double pitch)
{
  std::unique_ptr<DrakeJoint> joint;
  switch (floating) {
  case 0: {
    if (pitch == 0.0) {
      joint = std::make_unique<RevoluteJoint>(joint_name, transform_to_parent_body, joint_axis);
    } else if (std::isinf(pitch)) {
      joint = std::make_unique<PrismaticJoint>(joint_name, transform_to_parent_body, joint_axis);
    } else {
      joint = std::make_unique<HelicalJoint>(joint_name, transform_to_parent_body, joint_axis, pitch);
    }
    break;
  }
  case 1: {
    joint = std::make_unique<RollPitchYawFloatingJoint>(joint_name, transform_to_parent_body);
    break;
  }
  case 2: {
    joint = std::make_unique<QuaternionFloatingJoint>(joint_name, transform_to_parent_body);
    break;
  }
  default: {
    std::ostringstream stream;
    stream << "floating type " << floating << " not recognized.";
    throw std::runtime_error(stream.str());
    break;
  }
  }
  return joint;
}
<|endoftext|>