;/* execute me to compile with SAS/C
;SC SQL-CREATE.c IGNORE 73 DEBUG=SYMBOLFLUSH STRINGMERGE NOSTKCHK LINK
SC SQL-CREATE.c IGNORE 73 CPU=68020 OPT OPTTIME STRINGMERGE NOSTKCHK
SLink FROM SQL-CREATE.o TO SQL-CREATE SC SD STRIPDEBUG NOICONS
Delete SQL-CREATE.(o|lnk) QUIET
QUIT
*/
/**************************************************************************

SQL-CREATE.c  --  GoldED4-Scanner für SQL CREATE-Anweisungen

AUTOR(EN):        Thies Wellpott
ERSTELLUNG:       15.04.1998
COPYRIGHT:        (c) 1998 Thies Wellpott
BETRIEBSSYSTEM:   AmigaOS
COMPILER:         SAS/C 6.58

BESCHREIBUNG:

Scanner für GoldED Version 4.
Übergabeparameter:
- ULONG len       Länge der aktuellen Textzeile
- STRPTR *text    Zeiger auf aktuelle Textzeile
- ULONG *line     Zeiger auf aktuelle Zeilennummer
Rückgabewerte:
- ULONG return    Länge des gescannten Textes oder 0 für keinen Text
- STRPTR *text    Zeiger auf Text

Sucht SQL-CREATE-Anweisungen. Leerzeichen am Zeilenanfang werden ignoriert,
ein "OR REPLACE" (für Trigger, Prozeduren und Packages), "UNIQUE" (für
INDEX), "PUBLIC" (für SYNONYM, ROLLBACK SEGMENT, u. a.), "FORCE" oder
"NOFORCE" (für VIEW) nach dem "CREATE" ebenfalls. Die Groß-/Kleinschreibung
ist egal. Das Wort nach "CREATE [OR REPLACE] [UNIQUE|PUBLIC|[NO]FORCE]"
wird als Objekttyp angesehen, von dem die ersten vier Zeichen als erste
Spalte mitausgegeben werden.

Normalerweise werden nur einwortige Objekttypen akzeptiert, behandelte
Ausnahmen sind "PACKAGE [BODY]", "ROLLBACK SEGM[ENT]", "SNAPSHOT [LOG ON]",
"DATABASE LINK" und "SCHEMA AUTH[ORIZATION]". Der Objekttypkürzel wird
jeweils entsprechend angepaßt (z. B. wird aus "PACK" für eine Package
"PABO" für Package Body).

Das dann folgende Wort ist der Objektname. Alle aufeinanderfolgenden
SQL-Symbol-Zeichen (A-Z, a-z, 0-9, _, $, #, .) werden als Name angesehen.



FEHLER/EINSCHRÄNKUNGEN:

- Kommentare werden nicht berücksichtigt
- die Maximallänge eines gescannten Textes beträgt 60 Zeichen (wird intern
  überprüft und abgefangen)


ENTWICKLUNGSGESCHICHTE:

V1.000   15.04.1998   Thies Wellpott
- erste Version

V1.001   16.04.1998   Thies Wellpott
- spezielle Präfixe (PUBLIC, UNIQUE, etc.) und mehrwortige Objekttypen
  werden jetzt abgefangen

**************************************************************************/

#include "twscanner.h"



ULONG __asm golded_scanner(register __d0 ULONG len, register __a0 STRPTR *text,
      register __a1 ULONG *line)
{
   const char *version = "\0$VER: SQL-CREATE 1.1 " __AMIGADATE__;
   // Stringkonstante (in Code-Hunk) als Puffer mißbrauchen
   STRPTR puffer = "123456789012345678901234567890123456789012345678901234567890";
#define PUFFERLAENGE  60
   STRPTR zeichen = *text;

   // führende Leerzeichen ignorieren
   SKIPBLANKS(zeichen, len);

   // Minimaltext ist: "CREATE T x" (T für Typ, x für Bezeichner);
   // Leerzeichen nach "CREATE" nicht testen, falls es vergessen wurde
   if ( (len >= 10) && (STRICMP4(zeichen, 'C', 'R', 'E', 'A') && STRICMP2(zeichen, 'T', 'E')) )
   {
      UWORD laenge;                 // UWORD reicht für Länge, ULONG braucht nicht

      len -= 6;                     // "CREATE" ist schon übersprungen worden
      SKIPBLANKS(zeichen, len);

      // evt. "OR REPLACE" überspringen; prüfe, ob "OR " vorhanden;
      // Minimaltext "OR REPLACE T x"
      if ( (len >= 14) && IPSTRICMP2(zeichen, 'O', 'R') && ISBLANK(zeichen[2]) )
      {
         zeichen += 3;
         len -= 3;
         SKIPBLANKS(zeichen, len);
         // das nächste Wort (müßte "REPLACE" sein) überspringen
         while ( len && ISALPHA(*zeichen) )
         {
            zeichen++;
            len--;
         } // while
      } // if

      // evt. "PUBLIC " überspringen; Minimaltext "PUBLIC T x"
      if ( (len >= 10) && IPSTRICMP4(zeichen, 'P', 'U', 'B', 'L') &&
           IPSTRICMP2(zeichen + 4, 'I', 'C') && ISBLANK(zeichen[6]) )
      {
         zeichen += 7;
         len -= 7;
      } // if
      // oder evt. "UNIQUE " überspringen; Minimaltext "UNIQUE T x"
      else if ( (len >= 10) && IPSTRICMP4(zeichen, 'U', 'N', 'I', 'Q') &&
                IPSTRICMP2(zeichen + 4, 'U', 'E') && ISBLANK(zeichen[6]) )
      {
         zeichen += 7;
         len -= 7;
      } // else if
      // oder evt. "NOFORCE " überspringen; Minimaltext "NOFORCE T x"
      else if ( (len >= 11) && IPSTRICMP4(zeichen, 'N', 'O', 'F', 'O') &&
                IPSTRICMP3(zeichen + 4, 'R', 'C', 'E') && ISBLANK(zeichen[7]) )
      {
         zeichen += 8;
         len -= 8;
      } // else if
      // oder evt. "FORCE " überspringen; Minimaltext "FORCE T x"
      else if ( (len >= 10) && IPSTRICMP4(zeichen, 'F', 'O', 'R', 'C') &&
                (UPPER(zeichen[4]) == 'E') && ISBLANK(zeichen[5]) )
      {
         zeichen += 6;
         len -= 6;
      } // else if

      SKIPBLANKS(zeichen, len);
      // "zeichen" steht jetzt auf Beginn des Objekttyps

      *text = puffer;
      laenge = 0;

      // max. erste vier Zeichen des Objekttyps kopieren
      while ( len && (laenge < 4) && ISALPHA(*zeichen) )
      {
         *puffer++ = UPPER(*zeichen++);
         laenge++;
         len--;
      } // while

      if (laenge == 0)        // wohl kein Typ angegeben
         return 0;

      // restliche Zeichen des Objekttyps überspringen
      while ( len && ISALPHA(*zeichen) )
      {
         zeichen++;
         len--;
      } // while
      SKIPBLANKS(zeichen, len);
      // "zeichen" steht jetzt auf zweitem Objekttypwort oder Objektname

      // Sonderfälle von mehrwortigen Typen abfangen; Minimaltext "WORT x" (bei
      // allen möglichen folgenden Wörter sind mind. 4 Buchstaben vorhanden)
      if ( (laenge == 4) && (len >= 6) )
      {
         BOOL skip_alpha = FALSE;   // müssen am Ende nach Buchstaben übersprungen werden?

         // prüfe "PACKAGE BODY", mache aus Kürzel "PACK" "PABO"
         if ( IPSTRICMP4(puffer - 4, 'P', 'A', 'C', 'K') &&
              IPSTRICMP4(zeichen, 'B', 'O', 'D', 'Y') && ISBLANK(zeichen[4]) )
         {
            puffer[-2] = 'B';
            puffer[-1] = 'O';
            zeichen += 5;
            len -= 5;
         } // if
         // prüfe "ROLLBACK SEGMENT", mache aus Kürzel "ROLL" "ROBS"
         else if ( IPSTRICMP4(puffer - 4, 'R', 'O', 'L', 'L') &&
                   IPSTRICMP4(zeichen, 'S', 'E', 'G', 'M') )
         {
            puffer[-2] = 'B';
            puffer[-1] = 'S';
            zeichen += 4;
            len -= 4;
            skip_alpha = TRUE;
         } // else if
         // prüfe "SNAPSHOT LOG ON", mache aus Kürzel "SNAP" "SNLO"
         else if ( IPSTRICMP4(puffer - 4, 'S', 'N', 'A', 'P') &&
                   IPSTRICMP3(zeichen, 'L', 'O', 'G') && ISBLANK(zeichen[3]) )
         {
            puffer[-2] = 'L';
            puffer[-1] = 'O';
            zeichen += 4;
            len -= 4;
            SKIPBLANKS(zeichen, len);     // Leerzeichen bis "ON" überspringen
            skip_alpha = TRUE;
         } // else if
         // prüfe "DATABASE LINK", mache aus Kürzel "DATA" "DABL"
         else if ( IPSTRICMP4(puffer - 4, 'D', 'A', 'T', 'A') &&
                   IPSTRICMP4(zeichen, 'L', 'I', 'N', 'K') && ISBLANK(zeichen[4]) )
         {
            puffer[-2] = 'B';
            puffer[-1] = 'L';
            zeichen += 5;
            len -= 5;
         } // if
         // prüfe "SCHEMA AUTOHORIZATION", mache aus Kürzel "SCHE" "SCAU"
         else if ( IPSTRICMP4(puffer - 4, 'S', 'C', 'H', 'E') &&
                   IPSTRICMP4(zeichen, 'A', 'U', 'T', 'H') )
         {
            puffer[-2] = 'A';
            puffer[-1] = 'U';
            zeichen += 4;
            len -= 4;
            skip_alpha = TRUE;
         } // else if

         // wenn erforderlich, restliche Zeichen des Objekttyps überspringen
         if (skip_alpha)
         {
            while ( len && ISALPHA(*zeichen) )
            {
               zeichen++;
               len--;
            } // while
         } // if
         SKIPBLANKS(zeichen, len);
      } // if

      // "zeichen" steht jetzt auf Objektname

      // Objekttypkürzel mit Leerzeichen auffüllen bis insgesamt 5 Zeichen
      // geschrieben wurden
      do
      {
         *puffer++ = ' ';
         laenge++;
      } while (laenge < 5);

      if (!ISSQLSYM(*zeichen))      // Name beginnt nicht mit gültigem Zeichen?
         return 0;

      // Objektname kopieren
      while ( len && (laenge < PUFFERLAENGE) && ISSQLSYM(*zeichen) )
      {
         *puffer++ = *zeichen++;
         laenge++;
         len--;
      } // while

      return (ULONG)laenge;
   } // if

   return 0;
} // golded_scanner()



/**
#include <string.h>

int main(int argc, char *argv[])
{
   char text[128], *erg, laenge;
   
   strcpy(text, "crEATe table hummel");
   erg = text;
   laenge = golded_scanner(strlen(text), &erg, 0);
   erg[laenge] = 0;

   strcpy(text, "CREATE SEQUENCE Seq_Bereich MAXVALUE 999999 CYCLE;");
   erg = text;
   laenge = golded_scanner(strlen(text), &erg, 0);
   erg[laenge] = 0;

   strcpy(text, "  CREATE	 TABLE		Benutzergruppe_enthaltene_Bgrp$#%&");
   erg = text;
   laenge = golded_scanner(strlen(text), &erg, 0);
   erg[laenge] = 0;

   strcpy(text, "	CREATE  uniQUe  INDEX Bgrp_enth_Bgrp_Benutzergruppe ON");
   erg = text;
   laenge = golded_scanner(strlen(text), &erg, 0);
   erg[laenge] = 0;

   strcpy(text, "CreATE  snapshot  log   on   asb_Benutzer;");
   erg = text;
   laenge = golded_scanner(strlen(text), &erg, 0);
   erg[laenge] = 0;

   strcpy(text, "CREATE USER asb_ODBC_Abwesenheit IDENTIFIED BY asb_ODBC_Abwesenheit");
   erg = text;
   laenge = golded_scanner(strlen(text), &erg, 0);
   erg[laenge] = 0;

   strcpy(text, "CREATE OR REPLACE PROCEDURE asb.Exec_DDL(string VARCHAR2) AS");
   erg = text;
   laenge = golded_scanner(strlen(text), &erg, 0);
   erg[laenge] = 0;

   return 0;
} // main()
**/

