//------------------------------------------------------------
// ARGSPLIT.CPP
// Keith Larson
// TMS320 DSP Applications
// (c) Copyright 1995, 1996, 1997
// Texas Instruments Incorporated
//
// This is unsupported freeware code with no implied warranties or
// liabilities.  See the disclaimer document for details
//------------------------------------------------------------
#include <ctype.h>
#include <string.h>
#include "argsplit.h"
#include "symbols.h"
ARG arg[maxargs];
//-----------------------------------------------------
// repack_args repacks the contents of the arg list
// into the string destination pointed to by *ptr
//-----------------------------------------------------
void repack_args(char *ptr)
{ *ptr = 0;
  for(int x=0;x<maxargs;x++)
  { if(x<2)
    { if(*arg[x].s == 0)
      strcpy(arg[x].s," ");
    }
    if(*arg[x].s ==   0) break;
    ptr = strcat(ptr,arg[x].s);
    if(*arg[x+1].s == 0) break;
    if(x<2) strcat(ptr," ");
    else    strcat(ptr,",");
  }
}
//---------------------------------------------------------------
// return 1 if the character is ws, tab, line return of new line
//---------------------------------------------------------------
int WS_char(char *ptr)
{ switch(*ptr)
  { case  ' ':
    case '\r':
    case '\n':
    case '\t': return 1;
    default  : return 0;
  }
}
//---------------------------------------------------------------
// return 1 if the char is a valid character for the label field
//---------------------------------------------------------------
char valid_label_char(char *ptr)
{ if(isalpha(*ptr)) return 1;
  switch(*ptr)
  { case '_':
    case '~': return 1;
    default : return 0;
  }
}
//---------------------------------------------------------------
// return 1 if the string contains an invalid label
//---------------------------------------------------------------
int bad_label(char *ptr)
{
  if(valid_label_char(ptr))
  { ptr++;
    for(;;)
    { switch(*ptr)
      { case   0 :
        case '\r':
        case '\n':
        case  ';':
        case  ' ':
        case '\t': return 0;  // valid end of label field
        case  ':': ptr++; break;
      }
      if(valid_label_char(ptr)||isdigit(*ptr)) ptr++;
      else
      { switch(*ptr)
        { case   0 :
          case '\r':
          case '\n':
          case  ';':
          case  ' ':
          case '\t': return 0;  // valid end of label field
          case  '~':
          case  '_': ptr++; break;  // break for other allowable chars
          default  : return 1;
        }
      }
    }
  }
  else             // if non alpha, make sure label start is legal
  { switch(*ptr)
    { case    0:
      case '\r':
      case '\n':
      case  ';': // comment in col 1
      case  '*': // comment in col 1
      case  ' ':
      case '\t': return 0;  // valid end of label field
      default  : return 1;  // all others are invalid label start chars
    }
  }
}
//---------------------------------------------------------------------
// pack_and_split first compresses (removes WS) a line and then splits
// the line into the structure 'arg'
//
// returns
//
//   -2  Invalid character
//   -1  No line information (comment or all WS)
//    0  Only a label
//    1  opcode field
//    2  1st arg
//    3  2nd arg
//---------------------------------------------------------------------
int pack_and_split_arg(char *strg1)
{
  int n;
  char strings=0, literal = 0;
  char *p, *strg2;
  char argbuf[bufsize];
  char parallel = 0;
  strncpy(argbuf,strg1,bufsize-1);
  strg1 = argbuf;
  for(n=0;n<maxargs;n++) *arg[n].s = 0;        // zero all args
  if((*strg1=='*') || (*strg1==';')) return -1;  // string with comment start
  if(*strg1 == 0) return -1;
  //
  // Check for labels
  //
  if(valid_label_char(strg1))  // if valid label, put into arg[0].s
  {
    strg2=argend(strg1,0);
    if((*strg2==0)||(*strg2==';'))
    {
      if(*strg2==';') *strg2 = 0;
      if(strg1!=strg2)      // processed only a label
      { strncpy(arg[0].s,strg1,maxargsize-1);
        return 0;
      }
      return -2;          // should never get here!
    }
    *strg2   = 0;
    strncpy(arg[0].s,strg1,maxargsize-1);
    *strg2   = ' ';
    strg1 = argstart(strg2);
    if(*strg1 == 0) return 0;
    strg2 = strg1;
  }
  else
  {
    if(WS_char(strg1) != 1)  return -2; // Illegal start for label
    p = argstart(strg1);
    if(*p==0)                 return 0; // only WS
  }
  int x;
  for(x=1;x<maxargs;x++)
  {
    if(x==2)       // when x=2 (past opcode) compress remaining WS
    {
      if(strstr(arg[1].s,"||") != NULL) parallel = 1;
      p = strg1;
      strg2 = p;
      for(;;)
      { switch(*p)
        { case  '"': strings ^=1; break;
          case '\\': if(literal)
                     {
                       p++;
                    // if(*p=='\'') literal ^= 1;
                     }
                     break;
          case '\'': literal ^=1; break;
          case  ' ': if(strings) break;
                     if(literal) break;
          case '\t': if(parallel == 0)
                     { strcpy(p,p+1); p-- ;}
                     break;
          case '\r':
          case '\n':
          case   0 : goto break2;
          case  ';': if(strings || literal)
                     {
                       p--;
                       if(*p++ == '\\') break;
                       goto break2;
                     }
                     else
                     { *p=0; goto break2;}
          default  : break;
        }
        p++;
      }
break2:
      if(strings || literal)
         return -2;  // line is corrupt - size unknown
    }
    strg1=argstart(strg1); if(*strg1==0) break;
    switch(*strg1)
    { case '\'': if((strg2=strstr(strg1, "'\\''"))!=NULL)
                 {
                   strg2+=4;
                   break;
                 }
                 strg2 = strstr(strg1+1, "'"); strg2++; break;

      case  '"': strg2 = strstr(strg1+1,"\""); strg2++; break;
      default  : strg2 = argend(strg1,1);
    }

    if(*strg2 != 0) *strg2++ = 0;
//    strncpy(arg[x].s,strg1,maxargsize-1);
    strcpy(arg[x].s,strg1);
    if(*strg2==0) break;
    strg1 = strg2;
  }
  return x;
}
//-----------------------------------------------------
// Split the argument strings into seperate items
// returns the number of arguments found
//-----------------------------------------------------
int arg_split(char *ptr, char posn)
{ int n;
  char *ptr1, *ptr2;
  char argbuf[bufsize];
  strncpy(argbuf,ptr,bufsize-1);
  ptr = argbuf;
  strcat(ptr," ");
  for(n=0;n<maxargs;n++) *arg[n].s = 0;  // zero all args
  if((*ptr=='*') || (*ptr==';')) return 0;
  int x;
  for(x=posn;x<maxargs;x++)
  {
    ptr1=argstart(ptr); if(*ptr1==0) break;
    ptr2=argend  (ptr1,1); if(*ptr2==0) break;
    *ptr2++ = 0;
    strncpy(arg[x].s,ptr1,maxargsize-1);
    ptr = ptr2;
  }
  return x;
}
