Beispiel #1
0
Value *
read_value(Globals *g)
{
   Value *v;

   while (g->buflen > 0) {
      switch (PEEK_CHAR(g)) {
       case ' ':
       case '\t':
       case '\n':
       case '\0':
	 NEXT_CHAR(g);
	 break;
       case '\"':			/* begin string */
	 NEXT_CHAR(g);
	 return read_string(g);
	 break;
       case '(':
	 NEXT_CHAR(g);
	 return read_list(g);
	 break;
       case ')':
       case '.':
	 return NULL;
	 break;
       default:
	 return read_num_or_symbol(g);
	 break;
      }
   }
   ABORT(g, 23);
}
Beispiel #2
0
/**
 * Reads until encounter of a SPACE, CR or LF.
 * Writes read bytes int *buffer, without terminating SPACE, CR and LF.
 * Reallocs buffer if necessary.
 * Returns the last char read (i.e. either SPACE, CR, LF) or 0 on error.
 */
static char getToken(char** buffer, size_t* bufferLength)
{
    size_t writeIndex = 0;
    char c;
    NEXT_CHAR(c);
    while( (SPACE != c) && (CR != c) && (LF != c) )
    {
        if(writeIndex >= *bufferLength - 2)
        {
            if(MAX_TOKEN_LENGTH <= *bufferLength)
            {
                return 0;
            }
            if(0 == *bufferLength)
            {
                *bufferLength = MIN_TOKEN_LENGTH;
            }
            *bufferLength *= 2;
            *buffer = realloc(*buffer, *bufferLength);
        }
        (*buffer)[writeIndex] = c;
        writeIndex++;
        NEXT_CHAR(c);
    }
    (*buffer)[writeIndex] = 0;
    return c;
}
Beispiel #3
0
int gettag(FILE* html,char* tag)
{
    int c=0;
    char* p=tag;
    int lim=MAX_TAG-2;

    do {
        c=NEXT_CHAR(html);
        if (c==EOF) break;
    } while (c!='<');

    if (c==EOF) goto END_OF_FILE;

    SKIP_WS(html,c);

    do {
        if (lim--<0) break;
        *tag++=c;
        c=NEXT_CHAR(html);
    } while (!IS_SPACE(c));

    *tag='\0';
    return 1;
    END_OF_FILE:
    *tag='\0';
    return 0;

}
Beispiel #4
0
Value *
read_string(Globals *g)
{
   int strpos = 0;
   Value *v;
   char c;

#define ADD_CHAR(c)	\
   if (strpos >= g->strbuflen) \
      expand_strbuf(g);		\
   g->strbuf[strpos++] = (c)

   while (1) {
      switch (PEEK_CHAR(g)) {
       case '\"':
	 NEXT_CHAR(g);
	 v = ALLOC_VALUE();
	 v->tag = string;
	 v->value.s.length = strpos;
	 v->value.s.string = (char *) malloc(v->value.s.length);
	 bcopy(g->strbuf, v->value.s.string, v->value.s.length);
	 return v;
	 break;
       case '\\':
	 NEXT_CHAR(g);
	 if (read_escape(g, &c))
	    ADD_CHAR(c);
	 break;
       default:
	 ADD_CHAR(PEEK_CHAR(g));
	 NEXT_CHAR(g);
	 break;
      }
   }
}
Beispiel #5
0
Value *
read_list(Globals *g)
{
   Value *list;
   Value **tail;
   Value *v;

   tail = &list;
   while (g->buflen > 0) {
      if (NULL == (v = read_value(g))) {
	 switch (PEEK_CHAR(g)) {

	  case ')':
	    if (tail != NULL) {		/* if no last cdr yet, use nil */
	       *tail = NULL;
	    }
	    NEXT_CHAR(g);
	    return list;
	    break;

	  case '.':			/* set last cdr explicitly */
	    NEXT_CHAR(g);
	    *tail = read_value(g);
	    if (*tail == NULL) {
	       /* badly formed input ??? */
	       ABORT(g, 13);
	    }
	    tail = NULL;
	    break;

	  default:
	    /* badly formed input ??? */
	    ABORT(g, 13);
	    break;
	 }
      }
      else {			/* read a value, add it to the list */
	 if (NULL == tail) {
	    /* two values after a . in a list.  very bad! ??? */
	    ABORT(g, 13);
	 }
	 *tail = ALLOC_VALUE();
	 (*tail)->tag = cons;
	 (*tail)->value.cons.car = v;
	 tail = &(*tail)->value.cons.cdr;
      }
   }
}
Beispiel #6
0
int getproperty(FILE* html,char* property)
{
    int c=0;
    char* p=property;
    int outword=0;
    int lim=MAX_PROPERTY-2;

    SKIP_WS(html,c);
    do {
        if (IS_SPACE(c)) {outword=1;SKIP_WS(html,c);}
        if (c==EOF) goto END_OF_FILE;
        if (c=='=') break;
        if (outword) {property=p;outword=0;}
        *property++=c;
        if (lim--<0) break;
        c=NEXT_CHAR(html);
        if (c==EOF) goto END_OF_FILE;
    } while (c!='=');

    *property='\0';
    return 1;

    END_OF_FILE:
    *property='\0';
    return 0;
}
Beispiel #7
0
static GstASMScan *
gst_asm_scan_new (const gchar * buffer)
{
  GstASMScan *scan;

  scan = g_new0 (GstASMScan, 1);
  scan->buffer = buffer;
  NEXT_CHAR (scan);

  return scan;
}
Beispiel #8
0
static void
gst_asm_scan_string (GstASMScan * scan, gchar delim)
{
  gchar ch;
  gint i = 0;

  ch = THIS_CHAR (scan);
  while ((ch != delim) && (ch != '\0')) {
    if (i < MAX_RULE_LENGTH - 1)
      scan->val[i++] = ch;
    ch = NEXT_CHAR (scan);
    if (ch == '\\')
      ch = NEXT_CHAR (scan);
  }
  scan->val[i] = '\0';

  if (ch == delim)
    NEXT_CHAR (scan);

  scan->token = GST_ASM_TOKEN_STRING;
}
Beispiel #9
0
int getvalue(FILE* html,char* value)
{
    int c=0;

    int quote_non=0;
    int quote_sng=0;
    int quote_dbl=0;
    int lim=MAX_VALUE-2;

    SKIP_WS(html,c);
    switch (c)
    {
        case '\"' :
            quote_dbl=1;
            break;
        case '\'' :
            quote_sng=1;
            break;
        default :
            quote_non=1;
            *value++=c;
            if (lim--<0) break;
            break;
    }


    do
    {
        c=NEXT_CHAR(html);

        if (END_OF_VALUE(c))
            break;
        else {
            if (lim--<0) break;
            *value++=c;
            }

    } while (c!=EOF) ;
   
   if (c==EOF) goto END_OF_FILE;

    *value='\0';

   // printf("%s\n",value);
    return 1;

    END_OF_FILE:
    *value='\0';
   // printf("%s\n",value);
    return 0;
}
Beispiel #10
0
extern void print_byte(unsigned char *ptr, unsigned int size) {
    unsigned char *first_character;
    int            ch;

    first_character = FIRST_CHAR(ptr, size);

    for (ch=1; ch<=size; ++ch) {
        printf("%.2x", *first_character);
        fputc(' ', stdout);
        NEXT_CHAR(first_character);
    }

    fputc('\n', stdout);
}
Beispiel #11
0
static void
gst_asm_scan_identifier (GstASMScan * scan)
{
  gchar ch;
  gint i = 0;

  ch = THIS_CHAR (scan);
  /* real strips all spaces that are not inside quotes for identifiers */
  while ((IS_CHAR (ch) || IS_SPACE (ch))) {
    if (i < (MAX_RULE_LENGTH - 1) && !IS_SPACE (ch))
      scan->val[i++] = ch;
    ch = NEXT_CHAR (scan);
  }
  scan->val[i] = '\0';

  scan->token = GST_ASM_TOKEN_IDENTIFIER;
}
Beispiel #12
0
/**
 * This function performes a run-length decoding and writes back to
 * *dstpacket*, but no more than *maxsize* bytes.
 *
 * @param srcpacket: the encoded packet.
 * @param maxsize:   the maximal size of the decoded packet.
 */
static char          *gdbwrap_run_length_decode(char *dstpacket, const char *srcpacket,
						unsigned maxsize)
{
  /* Protocol specifies to take the following value and substract 29
     and repeat by this number the previous character.  Note that the
     compression may be used multiple times in a packet. */
  char              *encodestr;
  char               valuetocopy;
  uint8_t            numberoftimes;
  unsigned           iter;
  unsigned           strlenc;
  unsigned           check;

if (!srcpacket || !dstpacket)
return NULL;
  ASSERT(dstpacket != NULL && srcpacket != NULL &&
  	 srcpacket[0] != GDBWRAP_START_ENCODC);
  if (srcpacket != dstpacket)
    strncpy(dstpacket, srcpacket, maxsize);
  encodestr = strstr(dstpacket, GDBWRAP_START_ENCOD);
  check = strlen(dstpacket);
  while (encodestr != NULL)
    {
      /* This    is    OK   to    take    encodestr[-1],   since    we
	 assert(srcpacket[0] != GDBWRAP_START_ENCODC). */
      valuetocopy    = encodestr[-1];
      numberoftimes  = encodestr[1] - 29;
      ASSERT((check += numberoftimes) < maxsize);
      strlenc        = strlen(encodestr);
      /* We move the string to the right, then set the bytes. We
	 substract 2, because we have <number>*<char> where * and
	 <char> are filled with the value of <number> (ie 2 chars). */
      for (iter = 0; iter < strlenc; iter++)
	encodestr[strlenc + numberoftimes - iter - 2] = encodestr[strlenc - iter];
      memset(encodestr, valuetocopy, numberoftimes);
      encodestr = strstr(NEXT_CHAR(encodestr), GDBWRAP_START_ENCOD);
    }

  return dstpacket;
}
Beispiel #13
0
int
read_escape(Globals *g, char *c)
{
   int valid = 1;

   /* ??? handle octal \nnn notation?  urgh. */
   switch (PEEK_CHAR(g)) {
    case '\n':
      valid = 0;
      break;
    case 'n':
      *c = '\n';
      break;
    case 't':
      *c = '\t';
      break;
    default:
      *c = PEEK_CHAR(g);
      break;
   }
   NEXT_CHAR(g);
   return valid;
}
Beispiel #14
0
static void
gst_asm_scan_number (GstASMScan * scan)
{
  gchar ch;
  gint i = 0;
  gboolean have_float = FALSE;

  ch = THIS_CHAR (scan);
  /* real strips all spaces that are not inside quotes for numbers */
  while ((IS_NUMBER (ch) || IS_SPACE (ch))) {
    if (i < (MAX_RULE_LENGTH - 1) && !IS_SPACE (ch))
      scan->val[i++] = ch;
    if (ch == '.')
      have_float = TRUE;
    ch = NEXT_CHAR (scan);
  }
  scan->val[i] = '\0';

  if (have_float)
    scan->token = GST_ASM_TOKEN_FLOAT;
  else
    scan->token = GST_ASM_TOKEN_INT;
}
Beispiel #15
0
/*----------------------------------------------------------------------------*/
int http_readRequest(HttpRequest* request)
{
    /*
     * Request constitutes of
     * request-lineCRLF
     * Header1: *Value1CRLF
     * ...CRLF
     * CRLF
     * Body
     */
    enum {None, Cr1, Lf1, Cr2, Lf2} crLfReadingState;
    int numCrLf = 0;
    signed char c = 0;
    signed char c2 = 0;
    enum { BEFORE, READING, DONE }  readingState = BEFORE;
    /* Read method */
    while(DONE != readingState)
    {
        NEXT_CHAR(c);
        switch( toupper(c) )
        {
            case LF:
            case CR:
                if(BEFORE != readingState)
                {
                    LOG_CON(ERROR, socketFd, "Premature end of HTTP request\n");
                    return -1;
                }
                break;
            case 'G':
                request->type = GET;
                EXPECT('E', c);
                EXPECT('T', c);
                EXPECT(SPACE, c);
                readingState = DONE;
                LOG_CON(INFO, socketFd, "Got GET request");
                break;
            case 'H':
                request->type = HEAD;
                EXPECT('E', c);
                EXPECT('A', c);
                EXPECT('D', c);
                EXPECT(SPACE, c);
                readingState = DONE;
                LOG_CON(INFO, socketFd, "Got HEAD request");
                break;
            default:
                LOG_CON(ERROR, socketFd,
                        "Could not parse HTTP request - "
                        " Unsupported HTTP method?\n");
                return -1;
        };
    };
    if(SPACE != getToken(request->url, &request->urlMaxLength) )
    {
        LOG_CON(ERROR, socketFd, "Could not read URL for HTTP requst\n");
        return -1;
    }
    LOG_CON(INFO, socketFd, "Read URL");
    EXPECT('H', c);
    EXPECT('T', c);
    EXPECT('T', c);
    EXPECT('P', c);
    EXPECT('/', c);
    NEXT_CHAR(request->majVersion);
    EXPECT('.', c);
    NEXT_CHAR(request->minVersion);
    EXPECT(CR, c);
    EXPECT(LF, c);
    crLfReadingState = Lf1;
    /* Read until end of header */
    while(Lf2 != crLfReadingState)
    {
        NEXT_CHAR(c);
        if(CR == c)
        {
            if(Lf1 == crLfReadingState)
            {
                crLfReadingState = Cr2;
            }
            else
            {
                crLfReadingState = Cr1;
            }
        }
        else if(LF == c)
        {
            if(Cr1 == crLfReadingState)
            {
                crLfReadingState = Lf1;
            }
            else if(Cr2 == crLfReadingState)
            {
                crLfReadingState = Lf2;
            }
            else
            {
                crLfReadingState = None;
            }
        }
        else
        {
            crLfReadingState = None;
        }
    }
    /* Line should be terminated by CRLF, but LF might be missing */
    return 0;
}
Beispiel #16
0
static GstASMToken
gst_asm_scan_next_token (GstASMScan * scan)
{
  gchar ch;

  ch = THIS_CHAR (scan);

  /* skip spaces */
  while (IS_SPACE (ch))
    ch = NEXT_CHAR (scan);

  /* remove \ which is common in front of " */
  while (ch == '\\')
    ch = NEXT_CHAR (scan);

  switch (ch) {
    case '#':
      scan->token = GST_ASM_TOKEN_HASH;
      NEXT_CHAR (scan);
      break;
    case ';':
      scan->token = GST_ASM_TOKEN_SEMICOLON;
      NEXT_CHAR (scan);
      break;
    case ',':
      scan->token = GST_ASM_TOKEN_COMMA;
      NEXT_CHAR (scan);
      break;
    case '=':
      scan->token = GST_ASM_TOKEN_EQUAL;
      if (NEXT_CHAR (scan) == '=')
        NEXT_CHAR (scan);
      break;
    case '!':
      if (NEXT_CHAR (scan) == '=') {
        scan->token = GST_ASM_TOKEN_NOTEQUAL;
        NEXT_CHAR (scan);
      }
      break;
    case '&':
      scan->token = GST_ASM_TOKEN_AND;
      if (NEXT_CHAR (scan) == '&')
        NEXT_CHAR (scan);
      break;
    case '|':
      scan->token = GST_ASM_TOKEN_OR;
      if (NEXT_CHAR (scan) == '|')
        NEXT_CHAR (scan);
      break;
    case '<':
      scan->token = GST_ASM_TOKEN_LESS;
      if (NEXT_CHAR (scan) == '=') {
        scan->token = GST_ASM_TOKEN_LESSEQUAL;
        NEXT_CHAR (scan);
      }
      break;
    case '>':
      scan->token = GST_ASM_TOKEN_GREATER;
      if (NEXT_CHAR (scan) == '=') {
        scan->token = GST_ASM_TOKEN_GREATEREQUAL;
        NEXT_CHAR (scan);
      }
      break;
    case '$':
      scan->token = GST_ASM_TOKEN_DOLLAR;
      NEXT_CHAR (scan);
      break;
    case '(':
      scan->token = GST_ASM_TOKEN_LPAREN;
      NEXT_CHAR (scan);
      break;
    case ')':
      scan->token = GST_ASM_TOKEN_RPAREN;
      NEXT_CHAR (scan);
      break;
    case '"':
      NEXT_CHAR (scan);
      gst_asm_scan_string (scan, '"');
      break;
    case '\'':
      NEXT_CHAR (scan);
      gst_asm_scan_string (scan, '\'');
      break;
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      gst_asm_scan_number (scan);
      break;
    case '\0':
      scan->token = GST_ASM_TOKEN_EOF;
      break;
    default:
      gst_asm_scan_identifier (scan);
      break;
  }
  gst_asm_scan_print_token (scan);
  return scan->token;
}
Beispiel #17
0
Value *
read_num_or_symbol(Globals *g)
{
   Value *v;
   int strpos = 0;
   char c;
   int i;
   int is_integer;

#define ADD_CHAR(c)	\
   if (strpos >= g->strbuflen) \
      expand_strbuf(g);		\
   g->strbuf[strpos++] = (c)

   while (g->buflen > 0) {
      switch (PEEK_CHAR(g)) {
       case ' ':
       case '\t':
       case '\n':
       case '\0':
       case '\"':
       case '(':
       case ')':
       case '.':
	 goto done;
	 break;
       case '\\':
	 NEXT_CHAR(g);
	 ADD_CHAR(PEEK_CHAR(g));
	 NEXT_CHAR(g);
	 break;
       default:
	 ADD_CHAR(PEEK_CHAR(g));
	 NEXT_CHAR(g);
	 break;
      }
   }
   ABORT(g, 23);

 done:
   /* is this a number or a symbol? */
   /* assume integer to start */
   is_integer = 1;

   /* assume no empty strings? */

   /* if the first character is '+' or '-' and that's not the only */
   /* character it can still be an integer */
   if (strpos > 1 && (g->strbuf[0] == '-' || g->strbuf[0] == '+'))
      i = 1;
   else if (strpos == 1) {
      i = 0;
      is_integer = 0;
   }
   else
      i = 0;

   while (is_integer && i < strpos) {
      if (g->strbuf[i] < '0' || g->strbuf[i] > '9')
	 is_integer = 0;
      i++;
   }

   if (is_integer) {
      /* it's an integer */
      v = ALLOC_VALUE();
      v->tag = integer;
      ADD_CHAR('\0');
      v->value.integer.i = atoi(g->strbuf);
   }
   else {
      /* it's a symbol */
      if (3 == strpos &&
	  !bcmp(g->strbuf, "nil", 3)) {
	 v = NULL;
      } else {
	 v = ALLOC_VALUE();
	 v->tag = symbol;
	 v->value.s.length = strpos;
	 v->value.s.string = (char *) malloc(v->value.s.length);
	 bcopy(g->strbuf, v->value.s.string, v->value.s.length);
      }
   }
   return v;
}
Beispiel #18
0
token_t Scanner::NextToken(bool hungry)
// ----------------------------------------------------------------------------
//   Return the next token, and compute the token text and value
// ----------------------------------------------------------------------------
{
    textValue = "";
    tokenText = "";
    intValue = 0;
    realValue = 0.0;
    base = 0;

    // Check if input was opened correctly
    if (!input.good())
        return tokEOF;

    // Check if we unindented far enough for multiple indents
    hadSpaceBefore = true;
    while (indents.back() > indent)
    {
        indents.pop_back();
        return tokUNINDENT;
    }

    // Read next character
    int c = input.get();
    position++;

    // Skip spaces and check indendation
    hadSpaceBefore = false;
    while (isspace(c) && c != EOF)
    {
        hadSpaceBefore = true;
        if (c == '\n')
        {
            // New line: start counting indentation
            checkingIndent = true;
            lineStart = position;
        }
        else if (checkingIndent)
        {
            // Can't mix tabs and spaces
            if (c == ' ' || c == '\t')
            {
                if (!indentChar)
                    indentChar = c;
                else if (indentChar != c)
                    errors.Log(Error("Mixed tabs and spaces in indentation",
                                     position));
            }
        }

        // Keep looking for more spaces
        if (c == '\n')
            textValue += c;
        c = input.get();
        position++;
    } // End of space testing

    // Stop counting indentation
    if (checkingIndent)
    {
        input.unget();
        position--;
        checkingIndent = false;
        ulong column = position - lineStart;

        if (settingIndent)
        {
            // We set a new indent, for instance after opening paren
            indents.push_back(indent);
            indent = column;
            settingIndent = false;
            return tokNEWLINE;
        }
        else if (column > indent)
        {
            // Strictly deeper indent : report
            indent = column;
            indents.push_back(indent);
            return tokINDENT;
        }
        else if (column < indents.back())
        {
            // Unindenting: remove rightmost indent level
            ELFE_ASSERT(indents.size());
            indents.pop_back();
            indent = column;

            // If we unindented, but did not go as far as the
            // most recent indent, report inconsistency.
            if (indents.back() < column)
            {
                errors.Log(Error("Unindenting to the right "
                                 "of previous indentation", position));
                return tokERROR;
            }

            // Otherwise, report that we unindented
            // We may report multiple tokUNINDENT if we unindented deep
            return tokUNINDENT;
        }
        else
        {
            // Exactly the same indent level as before
            return tokNEWLINE;
        }
    }

    // Report end of input if that's what we've got
    if (input.eof())
	return tokEOF;

    // Clear spelling from whitespaces
    textValue = "";

    // Look for numbers
    if (isdigit(c))
    {
        bool floating_point = false;
        bool basedNumber = false;

        base = 10;
        intValue = 0;

        // Take integral part (or base)
        do
        {
            while (digit_values[c] < base)
            {
                intValue = base * intValue + digit_values[c];
                NEXT_CHAR(c);
                if (c == '_')       // Skip a single underscore
                {
                    IGNORE_CHAR(c);
                    if (c == '_')
                        errors.Log(Error("Two _ characters in a row look ugly",
                                         position));
                }
            }

            // Check if this is a based number
            if (c == '#' && !basedNumber)
            {
                base = intValue;
                if (base < 2 || base > 36)
                {
                    base = 36;
                    errors.Log(Error("The base $1 is not valid, not in 2..36",
                                     position).Arg(textValue));
                }
                NEXT_CHAR(c);
                intValue = 0;
                basedNumber = true;
            }
            else
            {
                basedNumber = false;
            }
        } while (basedNumber);

        // Check for fractional part
        realValue = intValue;
        if (c == '.')
        {
            int nextDigit = input.peek();
            if (digit_values[nextDigit] >= base)
            {
                // This is something else following an integer: 1..3, 1.(3)
                input.unget();
                position--;
                hadSpaceAfter = false;
                return tokINTEGER;
            }
            else
            {
                floating_point = true;
                double comma_position = 1.0;

                NEXT_CHAR(c);
                while (digit_values[c] < base)
                {
                    comma_position /= base;
                    realValue += comma_position * digit_values[c];
                    NEXT_CHAR(c);
                    if (c == '_')
                    {
                        IGNORE_CHAR(c);
                        if (c == '_')
                            errors.Log(Error("Two _ characters in a row "
                                             "look really ugly",
                                             position));
                    }
                }
            }
        }

        // Check if we have a second '#' at end of based number
        if (c == '#')
            NEXT_CHAR(c);

        // Check for the exponent
        if (c == 'e' || c == 'E')
        {
            NEXT_CHAR(c);

            uint exponent = 0;
            bool negative_exponent = false;

            // Exponent sign
            if (c == '+')
            {
                NEXT_CHAR(c);
            }
            else if (c == '-')
            {
                NEXT_CHAR(c);
                negative_exponent = true;
                floating_point = true;
            }

            // Exponent value
            while (digit_values[c] < 10)
            {
                exponent = 10 * exponent + digit_values[c];
                NEXT_CHAR(c);
                if (c == '_')
                    IGNORE_CHAR(c);
            }

            // Compute base^exponent
            double exponent_value = 1.0;
            double multiplier = base;
            while (exponent)
            {
                if (exponent & 1)
                    exponent_value *= multiplier;
                exponent >>= 1;
                multiplier *= multiplier;
            }

            // Compute actual value
            if (negative_exponent)
                realValue /= exponent_value;
            else
                realValue *= exponent_value;
            intValue = (ulong) realValue;
        }

        // Return the token
        input.unget();
        position--;
        hadSpaceAfter = isspace(c);
        return floating_point ? tokREAL : tokINTEGER;
    } // Numbers
Beispiel #19
0
// !! this function modifies data pointed with sCmdLine parameter!
size_t srvParseCmdLine(cEnvironmentHelper* pEnvironmentHelper, tstring sCmdLine, tcstring sDefaultDir, tcstring* params, size_t max_params_count, bool bInterpreteur)
{
	assert((params && max_params_count) || (!params && !max_params_count));
	bool bCMD = bInterpreteur;
	size_t params_count = 0;
	tstring pwchPtr = sCmdLine;
	tstring param;
	tchar wc;
	if (sCmdLine == NULL)
		return 0;
	if (!params && !max_params_count)
		max_params_count = SIZE_MAX;
	wc = tstrchar(pwchPtr);
	while (wc>0 && wc<=' ')
		wc = NEXT_CHAR();
	sCmdLine = pwchPtr;
	if (wc != '\"') // first param not quoted
	{
		wc = tstrchar(pwchPtr);
		while (wc)
		{
			// find delimiter
			while (wc != 0 && !IS_DELIM(wc, bCMD))
				wc = NEXT_CHAR();
			tstrchar(pwchPtr) = 0;
			tstring file = pEnvironmentHelper->PathFindExecutable(sCmdLine, sDefaultDir); // check long file name without quotes
			tstrchar(pwchPtr) = wc;
			if (file)
			{
				if (params)
				{
					params[0] = sCmdLine;
					tstrchar(pwchPtr) = 0;
				}
				params_count++;
				sCmdLine = pwchPtr;
				if (wc) // we have more args
					sCmdLine++;
				tstrfree(file);
				break;
			}
			if (wc)
				wc = NEXT_CHAR();
		}
	}
	pwchPtr = sCmdLine;
	while (params_count < max_params_count)
	{
		wc = tstrchar(pwchPtr);
		
		// skip delimiters at start
		while (wc != 0 && IS_DELIM(wc, bCMD))
			wc = NEXT_CHAR();
		
		if (wc == 0) // end reached
			break; 

		if (wc == '\"') // quoted param
		{
			wc = NEXT_CHAR();
			if (bCMD && wc == '\"')
				wc = NEXT_CHAR();
			
			if (wc == 0) // end reached
				break;

			param = pwchPtr;
			while (wc != 0 && wc != '\"')
				wc = NEXT_CHAR();
		}
		else
		{
			//if (wc != '/') // if not switch
			param = pwchPtr;
			// modified by Sobko was: while (wc != 0 && !IS_DELIM(wc) && wc != '\"')
			while (wc != 0 && !IS_DELIM(wc, bCMD) && wc != '\"')
				wc = NEXT_CHAR();
		}
		if (param != pwchPtr)
		{
			if (params)
			{
				params[params_count] = param;
				tstrchar(pwchPtr) = 0; // zero terminate parameter
			}
			if (params_count == 0)
			{
				tchar c = tstrchar(pwchPtr);
				tstrchar(pwchPtr) = 0; // zero terminate parameter
				if (tstring file = pEnvironmentHelper->PathFindExecutable(param, sDefaultDir)) // check long file name without quotes
				{
					if (srvComparePath(pEnvironmentHelper, file, _T("%ComSpec%")))
						bCMD = true;
					tstrfree(file);
				}
				tstrchar(pwchPtr) = c; // restore terminate parameter
			}
			params_count++;
		}

		if (wc == 0) // end reached
			break;
		
		wc = NEXT_CHAR();
	}

	return params_count;
}
Beispiel #20
0
/* msg_quote_phrase_or_addr
 *
 * Given a single mailbox, this quotes the characters in it which need
 * to be quoted; it writes into `address' and returns a new length.
 * `address' is assumed to be long enough; worst case, its size will
 * be (N*2)+2.
 */
static int
msg_quote_phrase_or_addr(char *address, PRInt32 length, PRBool addr_p)
{
    int quotable_count = 0, in_quote = 0;
    int unquotable_count = 0;
    PRInt32 new_length, full_length = length;
    char *in, *out, *orig_out, *atsign = NULL, *orig_address = address;
    PRBool user_quote = PR_FALSE;
    PRBool quote_all = PR_FALSE;

    /* If the entire address is quoted, fall out now. */
    if (address[0] == '\"' && address[length - 1] == '\"')
        return length;

    /* Check to see if there is a routing prefix.  If there is one, we can
     * skip quoting it because by definition it can't need to be quoted.
     */
    if (addr_p && *address && *address == '@')
    {
        for (in = address; *in; NEXT_CHAR(in))
        {
            if (*in == ':')
            {
                length -= ++in - address;
                address = in;
                break;
            }
            else if (!IS_DIGIT(*in) && !IS_ALPHA(*in) && *in != '@' && *in != '.')
                break;
        }
    }

    for (in = address; in < address + length; NEXT_CHAR(in))
    {
        if (*in == 0)
            return full_length; /* #### horrible kludge... */

        else if (*in == '@' && addr_p && !atsign && !in_quote)
        {
            /* Exactly one unquoted at-sign is allowed in an address. */
            if (atsign)
                quotable_count++;
            atsign = in;

            /* If address is of the form '"userid"@somewhere.com' don't quote
             * the quotes around 'userid'.  Also reset the quotable count, since
             * any quotables we've seen are already inside quotes.
             */
            if (address[0] == '\"' && in > address + 2 && *(in - 1) == '\"' && *(in - 2) != '\\')
                unquotable_count -= 2, quotable_count = 0, user_quote = PR_TRUE;
        }

        else if (*in == '\\')
        {
            if (in + 1 < address + length && (*(in + 1) == '\\' || *(in + 1) == '\"'))
                /* If the next character is a backslash or quote, this backslash */
                /* is an escape backslash; ignore it and the next character.     */
                in++;
            else
                /* If the name contains backslashes or quotes, they must be escaped. */
                unquotable_count++;
        }

        else if (*in == '\"')
            /* If the name contains quotes, they must be escaped. */
            unquotable_count++, in_quote = !in_quote;

        else if (  /* *in >= 127 || *in < 0  ducarroz: 8bits characters will be mime encoded therefore they are not a problem
             ||*/ (*in == ';' && !addr_p) || *in == '$' || *in == '(' || *in == ')'
            || *in == '<' || *in == '>' || *in == '@' || *in == ',')
            /* If the name contains control chars or Header specials, it needs to
             * be enclosed in quotes.  Double-quotes and backslashes will be dealt
             * with separately.
             *
             * The ":" character is explicitly not in this list, though Header says
             * it should be quoted, because that has been seen to break VMS
             * systems.  (Rather, it has been seen that there are Unix SMTP servers
             * which accept RCPT TO:<host::user> but not RCPT TO:<"host::user"> or
             * RCPT TO:<host\:\:user>, which is the syntax that VMS/DECNET hosts
             * use.
             *
             * For future reference: it is also claimed that some VMS SMTP servers
             * allow \ quoting but not "" quoting; and that sendmail uses self-
             * contradcitory quoting conventions that violate both RFCs 821 and
             * 822, so any address quoting on a sendmail system will lose badly.
             *
             * The ";" character in an address is a group delimiter, therefore it
             * should not be quoted in that case.
             */
            quotable_count++;

        else if (!atsign && (*in == '[' || *in == ']'))
            /* Braces are normally special characters, except when they're
             * used for domain literals (e.g. johndoe@[127.0.0.1].acme.com).
             */
            quotable_count++;

        else if (addr_p && *in == ' ')
            /* Naked spaces are allowed in names, but not addresses. */
            quotable_count++;

        else if (   !addr_p
                    && (*in == '.' || *in == '!' || *in == '$' || *in == '%'))
            /* Naked dots are allowed in addresses, but not in names.
             * The other characters (!$%) are technically allowed in names, but
             * are surely going to cause someone trouble, so we quote them anyway.
             */
            quotable_count++;
    }

    if (quotable_count == 0 && unquotable_count == 0)
        return full_length;

    /* We must quote the entire string if there are quotables outside the user
     * quote.
     */
    if (!atsign || (user_quote && quotable_count > 0))
        quote_all = PR_TRUE, atsign = NULL;

    /* Add 2 to the length for the quotes, plus one for each character
     * which will need a backslash, plus one for a null terminator.
     */
    new_length = length + quotable_count + unquotable_count + 3;

    in = address;
    out = orig_out = (char *)PR_Malloc(new_length);
    if (!out)
    {
        *orig_address = 0;
        return 0;
    }

    /* Start off with a quote.
     */
    *out++ = '\"';

    while (*in)
    {
        if (*in == '@')
        {
            if (atsign == in)
                *out++ = '\"';
            *out++ = *in++;
            continue;
        }
        else if (*in == '\"')
        {
            if (!user_quote || (in != address && in != atsign - 1))
                *out++ = '\\';
            *out++ = *in++;
            continue;
        }
        else if (*in == '\\')
        {
            if (*(in + 1) == '\\' || *(in + 1) == '\"')
                *out++ = *in++;
            else
                *out++ = '\\';
            *out++ = *in++;
            continue;
        }
        else
            COPY_CHAR(out, in);

        NEXT_CHAR(in);
    }

    /* Add a final quote if we are quoting the entire string.
     */
    if (quote_all)
        *out++ = '\"';
    *out++ = 0;

    NS_ASSERTION(new_length >= (out - orig_out), "");
    memcpy(address, orig_out, new_length);
    PR_FREEIF(orig_out); /* make sure we release the string we allocated */

    return full_length + unquotable_count + 2;
}
Beispiel #21
0
/* msg_unquote_phrase_or_addr
 *
 * Given a name or address that might have been quoted
 * it will take out the escape and double quotes
 * The caller is responsible for freeing the resulting
 * string.
 */
static nsresult
msg_unquote_phrase_or_addr(const char *line, PRBool preserveIntegrity, char **lineout)
{
    if (!line || !lineout)
        return NS_OK;

    /* If the first character isn't a double quote, there is nothing to do
     */
    if (*line != '\"')
    {
        *lineout = strdup(line);
        if (!*lineout)
            return NS_ERROR_OUT_OF_MEMORY;
        else
            return NS_OK;
    }

    /* in preserveIntegrity mode, we must preserve the quote if the name contains a comma */
    if (preserveIntegrity)
    {
        const char * open_quote = nsnull;
        const char * comma = nsnull;;
        const char * at_sign = nsnull;
        const char * readPos = line + 1;

        while (*readPos)
        {
            if (*readPos == ',')
            {
                if (!open_quote)
                    comma = readPos;
            }
            else if (*readPos == '@')
            {
                at_sign = readPos;
                break;
            }
            else if (*readPos == '"')
            {
                if (!open_quote)
                    open_quote = readPos;
                else
                    open_quote = nsnull;
            }

            readPos ++;
        }

        if (comma && at_sign)
        {
            *lineout = strdup(line);
            if (!*lineout)
                return NS_ERROR_OUT_OF_MEMORY;
            else
                return NS_OK;
        }
    }

    /* Don't copy the first double quote
     */
    *lineout = strdup(line + 1);
    if (!*lineout)
        return NS_ERROR_OUT_OF_MEMORY;

    const char *lineptr = line + 1;
    char *outptr = *lineout;
    PRBool escaped = PR_FALSE;

    while (*lineptr)
    {
        /* If the character is an '\' then output the character that was
         * escaped.  If it was part of the quote then don't output it.
         */
        if (*lineptr == '\\')
        {
            escaped = PR_TRUE;
            lineptr++;
        }
        if (*lineptr == '\"' && !escaped)
            lineptr++;
        escaped = PR_FALSE;

        if (*lineptr)
        {
            COPY_CHAR(outptr, lineptr);
            NEXT_CHAR(lineptr);
        }
    }
    *outptr = '\0';

    return NS_OK;
}
Beispiel #22
0
/*
 * NumPyOS_ascii_ftolf:
 *      * fp: FILE pointer
 *      * value: Place to store the value read
 *
 * Similar to PyOS_ascii_strtod, except that it reads input from a file.
 *
 * Similarly to fscanf, this function always consumes leading whitespace,
 * and any text that could be the leading part in valid input.
 *
 * Return value: similar to fscanf.
 *      * 0 if no number read,
 *      * 1 if a number read,
 *      * EOF if end-of-file met before reading anything.
 */
NPY_NO_EXPORT int
NumPyOS_ascii_ftolf(FILE *fp, double *value)
{
    char buffer[FLOAT_FORMATBUFLEN + 1];
    char *endp;
    char *p;
    int c;
    int ok;

    /*
     * Pass on to PyOS_ascii_strtod the leftmost matching part in regexp
     *
     *     \s*[+-]? ( [0-9]*\.[0-9]+([eE][+-]?[0-9]+)
     *              | nan  (  \([:alphanum:_]*\) )?
     *              | inf(inity)?
     *              )
     *
     * case-insensitively.
     *
     * The "do { ... } while (0)" wrapping in macros ensures that they behave
     * properly eg. in "if ... else" structures.
     */

#define END_MATCH()                                                         \
        goto buffer_filled

#define NEXT_CHAR()                                                         \
        do {                                                                \
            if (c == EOF || endp >= buffer + FLOAT_FORMATBUFLEN)            \
                END_MATCH();                                                \
            *endp++ = (char)c;                                              \
            c = getc(fp);                                                   \
        } while (0)

#define MATCH_ALPHA_STRING_NOCASE(string)                                   \
        do {                                                                \
            for (p=(string); *p!='\0' && (c==*p || c+('a'-'A')==*p); ++p)   \
                NEXT_CHAR();                                                \
            if (*p != '\0') END_MATCH();                                    \
        } while (0)

#define MATCH_ONE_OR_NONE(condition)                                        \
        do { if (condition) NEXT_CHAR(); } while (0)

#define MATCH_ONE_OR_MORE(condition)                                        \
        do {                                                                \
            ok = 0;                                                         \
            while (condition) { NEXT_CHAR(); ok = 1; }                      \
            if (!ok) END_MATCH();                                           \
        } while (0)

#define MATCH_ZERO_OR_MORE(condition)                                       \
        while (condition) { NEXT_CHAR(); }

    /* 1. emulate fscanf EOF handling */
    c = getc(fp);
    if (c == EOF) {
        return EOF;
    }
    /* 2. consume leading whitespace unconditionally */
    while (NumPyOS_ascii_isspace(c)) {
        c = getc(fp);
    }

    /* 3. start reading matching input to buffer */
    endp = buffer;

    /* 4.1 sign (optional) */
    MATCH_ONE_OR_NONE(c == '+' || c == '-');

    /* 4.2 nan, inf, infinity; [case-insensitive] */
    if (c == 'n' || c == 'N') {
        NEXT_CHAR();
        MATCH_ALPHA_STRING_NOCASE("an");

        /* accept nan([:alphanum:_]*), similarly to strtod */
        if (c == '(') {
            NEXT_CHAR();
            MATCH_ZERO_OR_MORE(NumPyOS_ascii_isalnum(c) || c == '_');
            if (c == ')') {
                NEXT_CHAR();
            }
        }
        END_MATCH();
    }
    else if (c == 'i' || c == 'I') {
        NEXT_CHAR();
        MATCH_ALPHA_STRING_NOCASE("nfinity");
        END_MATCH();
    }

    /* 4.3 mantissa */
    MATCH_ZERO_OR_MORE(NumPyOS_ascii_isdigit(c));

    if (c == '.') {
        NEXT_CHAR();
        MATCH_ONE_OR_MORE(NumPyOS_ascii_isdigit(c));
    }

    /* 4.4 exponent */
    if (c == 'e' || c == 'E') {
        NEXT_CHAR();
        MATCH_ONE_OR_NONE(c == '+' || c == '-');
        MATCH_ONE_OR_MORE(NumPyOS_ascii_isdigit(c));
    }

    END_MATCH();

buffer_filled:

    ungetc(c, fp);
    *endp = '\0';

    /* 5. try to convert buffer. */
    *value = NumPyOS_ascii_strtod(buffer, &p);

    /* return 1 if something read, else 0 */
    return (buffer == p) ? 0 : 1;
}
Beispiel #23
0
/* msg_parse_Header_addresses
 *
 * Given a string which contains a list of Header addresses, parses it into
 * their component names and mailboxes.
 *
 * The returned value is the number of addresses, or a negative error code;
 * the names and addresses are returned into the provided pointers as
 * consecutive null-terminated strings.  It is up to the caller to free them.
 * Note that some of the strings may be zero-length.
 *
 * Either of the provided pointers may be NULL if the caller is not interested
 * in those components.
 *
 * quote_names_p and quote_addrs_p control whether the returned strings should
 * be quoted as Header entities, or returned in a more human-presentable (but
 * not necessarily parsable) form.
 *
 * If first_only_p is true, then only the first element of the list is
 * returned; we don't bother parsing the rest.
 */
static int msg_parse_Header_addresses (const char *line, char **names, char **addresses,
                                       PRBool quote_names_p, PRBool quote_addrs_p, PRBool first_only_p)
{
    PRUint32 addr_count = 0;
    size_t line_length;
    const char *line_end;
    const char *this_start;
    char *name_buf = 0, *name_out, *name_start;
    char *addr_buf = 0, *addr_out, *addr_start;

    if (names)
        *names = 0;
    if (addresses)
        *addresses = 0;
    NS_ASSERTION(line, "");
    if (!line)
        return -1;
    line_length = strlen(line);
    if (line_length == 0)
        return 0;

    name_buf = (char *)PR_Malloc(line_length * 2 + 10);
    if (!name_buf)
        return NS_ERROR_OUT_OF_MEMORY;

    addr_buf = (char *)PR_Malloc(line_length * 2 + 10);
    if (!addr_buf)
    {
        FREEIF(name_buf);
        return NS_ERROR_OUT_OF_MEMORY;
    }

    line_end = line;
    addr_out = addr_buf;
    name_out = name_buf;
    name_start = name_buf;
    addr_start = addr_buf;
    this_start = line;

    /* Skip over extra whitespace or commas before addresses.
     */
    while (*line_end && (IS_SPACE(*line_end) || *line_end == ','))
        NEXT_CHAR(line_end);

    while (*line_end)
    {
        PRUint32 paren_depth = 0;
        const char *oparen = 0;
        const char *mailbox_start = 0;
        const char *mailbox_end = 0;

        while (   *line_end
                  && !(   *line_end == ',' && paren_depth <= 0 /* comma is ok inside () */
                          && (!mailbox_start || mailbox_end)))    /* comma is ok inside <> */
        {
            if (*line_end == '\\')
            {
                line_end++;
                if (!*line_end) /* otherwise, we walk off end of line, right? */
                    break;
            }
            else if (*line_end == '\"')
            {
                int leave_quotes = 0;

                line_end++;  /* remove open " */

                /* handle '"John.Van Doe"@space.com' case */
                if (paren_depth == 0 && !mailbox_start)
                {
                    const char *end_quote;
                    /* search for the closing quote but ignored escaped quote \" */
                    for (end_quote = line_end;; end_quote++)
                    {
                        end_quote = PL_strchr(end_quote, '"');
                        if (!end_quote || *(end_quote - 1) != '\\')
                            break;
                    }
                    const char *mailbox = end_quote ? PL_strchr(end_quote, '<') : (char *)NULL;
                    const char *comma = end_quote ? PL_strchr(end_quote, ',') : (char *)NULL;
                    if (!mailbox || (comma && comma < mailbox))
                    {
                        leave_quotes = 1; /* no mailbox for this address */
                        *addr_out++ = '\"';
                    }
                }

                while (*line_end)
                {
                    if (*line_end == '\\')
                    {
                        line_end++;
                        if (paren_depth == 0 && (*line_end == '\\' || *line_end == '\"'))
                            *addr_out++ = *line_end++;
                        continue;
                    }
                    else if (*line_end == '\"')
                    {
                        line_end++;  /* remove close " */
                        break;
                    }

                    if (paren_depth == 0)
                        COPY_CHAR(addr_out, line_end);

                    NEXT_CHAR(line_end);
                }
                if (leave_quotes) *addr_out++ = '\"';
                continue;
            }

            if (*line_end == '(')
            {
                if (paren_depth == 0)
                    oparen = line_end;
                paren_depth++;
            }
            else if (*line_end == '<' && paren_depth == 0)
            {
                mailbox_start = line_end;
            }
            else if (*line_end == '>' && mailbox_start && paren_depth == 0)
            {
                mailbox_end = line_end;
            }
            else if (*line_end == ')' && paren_depth > 0)
            {
                paren_depth--;
                if (paren_depth == 0)
                {
                    const char *s = oparen + 1;

                    /* Copy the chars inside the parens onto the "name" buffer. */

                    /* Push out some whitespace before the paren, if
                                       * there is non-whitespace there already.
                                       */
                    if (name_out > name_start && !IS_SPACE(name_out [-1]))
                        *name_out++ = ' ';

                    /* Skip leading whitespace.
                     */
                    while (IS_SPACE(*s) && s < line_end)
                        s++;

                    while (s < line_end)
                    {
                        /* Strip out " within () unless backslashed
                         */
                        if (*s == '\"')
                        {
                            s++;
                            continue;
                        }

                        if (*s == '\\') /* remove one \ */
                            s++;

                        if (IS_SPACE(*s) && name_out > name_start && IS_SPACE(name_out[-1]))
                            /* collapse consecutive whitespace */;
                        else
                            COPY_CHAR(name_out, s);

                        NEXT_CHAR(s);
                    }
                    oparen = 0;
                }
            }
            else
            {
                /* If we're not inside parens or a <mailbox>, tack this
                 * on to the end of the addr_buf.
                 */
                if (paren_depth == 0 && (!mailbox_start || mailbox_end))
                {
                    /* Eat whitespace at the beginning of the line,
                     * and eat consecutive whitespace within the line.
                     */
                    if (IS_SPACE(*line_end)
                            && (addr_out == addr_start || IS_SPACE(addr_out[-1])))
                        /* skip it */;
                    else
                        COPY_CHAR(addr_out, line_end);
                }
            }

            NEXT_CHAR(line_end);
        }

        /* Now we have extracted a single address from the comma-separated
           * list of addresses.  The characters have been divided among the
           * various buffers: the parts inside parens have been placed in the
           * name_buf, and everything else has been placed in the addr_buf.
           * Quoted strings and backslashed characters have been `expanded.'
           *
           * If there was a <mailbox> spec in it, we have remembered where it was.
           * Copy that on to the addr_buf, replacing what was there, and copy the
           * characters not inside <> onto the name_buf, replacing what is there
           * now (which was just the parenthesized parts.)  (And we need to do the
           * quote and backslash hacking again, since we're coming from the
           * original source.)
           *
           * Otherwise, we're already done - the addr_buf and name_buf contain
           * the right data already (de-quoted.)
           */
        if (mailbox_end)
        {
            const char *s;
            NS_ASSERTION(*mailbox_start == '<', "");
            NS_ASSERTION(*mailbox_end == '>', "");

            /* First, copy the name.
             */
            name_out = name_start;
            s = this_start;

            /* Skip leading whitespace.
             */
            while (IS_SPACE(*s) && s < mailbox_start)
                s++;

            /* Copy up to (not including) the <
             */
            while (s < mailbox_start)
            {
                if (*s == '\"' && !quote_names_p)
                {
                    s++;
                    continue;
                }
                if (*s == '\\' && !quote_names_p)
                {
                    s++;
                    if (s < mailbox_start && (*s == '\\' || *s == '\"'))
                        *name_out++ = *s++;
                    continue;
                }
                if (IS_SPACE(*s) && name_out > name_start && IS_SPACE(name_out[-1]))
                    /* collapse consecutive whitespace */;
                else
                    COPY_CHAR(name_out, s);

                NEXT_CHAR(s);
            }

            /* Push out one space.
             */
            TRIM_WHITESPACE(name_start, name_out, ' ');
            s = mailbox_end + 1;

            /* Skip whitespace after >
             */
            while (IS_SPACE(*s) && s < line_end)
                s++;

            /* Copy from just after > to the end.
             */
            while (s < line_end)
            {
                if (*s == '\"' && !quote_names_p)
                {
                    s++;
                    continue;
                }
                if (*s == '\\' && !quote_names_p)
                {
                    s++;
                    if (s  < line_end && (*s == '\\' || *s == '\"'))
                        *name_out++ = *s++;
                    continue;
                }
                if (IS_SPACE(*s) && name_out > name_start && IS_SPACE(name_out[-1]))
                    /* collapse consecutive whitespace */;
                else
                    COPY_CHAR(name_out, s);

                NEXT_CHAR(s);
            }

            TRIM_WHITESPACE(name_start, name_out, 0);

            /* Now, copy the address.
             */
            mailbox_start++;
            addr_out = addr_start;
            s = mailbox_start;

            /* Skip leading whitespace.
             */
            while (IS_SPACE(*s) && s < mailbox_end)
                s++;

            /* Copy up to (not including) the >
             */
            while (s < mailbox_end)
            {
                if (*s == '\"' && !quote_addrs_p)
                {
                    s++;
                    continue;
                }
                if (*s == '\\' && !quote_addrs_p)
                {
                    s++;
                    if (s < mailbox_end && (*s == '\\' || *s == '\"'))
                        *addr_out++ = *s++;
                    continue;
                }
                COPY_CHAR(addr_out, s);
                NEXT_CHAR(s);
            }

            TRIM_WHITESPACE(addr_start, addr_out, 0);
        }
        /* No component of <mailbox> form.
         */
        else
        {
            TRIM_WHITESPACE(addr_start, addr_out, 0);
            TRIM_WHITESPACE(name_start, name_out, 0);
        }

        /* Now re-quote the names and addresses if necessary.
         */
#ifdef BUG11892
        // **** jefft - we don't want and shouldn't to requtoe the name, this
        // violate the RFC822 spec
        if (quote_names_p && names)
        {
            int L = name_out - name_start - 1;
            L = msg_quote_phrase_or_addr(name_start, L, PR_FALSE);
            name_out = name_start + L + 1;
        }
#endif

        if (quote_addrs_p && addresses)
        {
            int L = addr_out - addr_start - 1;
            L = msg_quote_phrase_or_addr(addr_start, L, PR_TRUE);
            addr_out = addr_start + L + 1;
        }

        addr_count++;

        /* If we only want the first address, we can stop now.
         */
        if (first_only_p)
            break;

        if (*line_end)
            NEXT_CHAR(line_end);

        /* Skip over extra whitespace or commas between addresses. */
        while (*line_end && (IS_SPACE(*line_end) || *line_end == ','))
            line_end++;

        this_start = line_end;
        name_start = name_out;
        addr_start = addr_out;
    }

    /* Make one more pass through and convert all whitespace characters
     * to SPC.  We could do that in the first pass, but this is simpler.
     */
    {
        char *s;
        for (s = name_buf; s < name_out; NEXT_CHAR(s))
            if (IS_SPACE(*s) && *s != ' ')
                *s = ' ';
        for (s = addr_buf; s < addr_out; NEXT_CHAR(s))
            if (IS_SPACE(*s) && *s != ' ')
                *s = ' ';
    }

    if (names)
        *names = name_buf;
    else
        PR_Free(name_buf);

    if (addresses)
        *addresses = addr_buf;
    else
        PR_Free(addr_buf);

    return addr_count;
}