#include "agnt_mon.h"

/*=======================================================================
  (C) Copyright SAP AG, 2002

         
 Author  : Dostert/SAP
 Project : Get data from R/3 using XMB
 Using   : RFCSDK 
 ========================================================================*/

/*------------------------------------------------------------------*/
/*  Global Var.						            */
/*------------------------------------------------------------------*/

/* Array of MoniHandles */
AlMoniHandle_T   *MoniHandles;

/* Array of MoniTemplates*/
AlMoniTemplate_T *MoniTempl;

/*------------------------------------------------------------------*/
/*  Prototyp						            */
/*------------------------------------------------------------------*/

int AlWildcardfit (char *wildcard, char *test);
ez_cfg_t * get_cfg_template( ez_cfg_t *ez_cfg, int NrOfCfgs, char *value);


/*------------------------------------------------------------------*/
/*  parse_login_file						    */
/*------------------------------------------------------------------*/
char *  parse_login_file(char *templ ) {
	dictionary  *ini ;
	int sec_count,
                i, j;
        char *sec_name;
        char sec_name_cmp [255];
	char sec_attr [255];
	char *login = NULL;


	ini = iniparser_load(AGENT_LOGIN_FILE);

	if (ini==NULL) {
                fprintf(stderr, "cannot parse file [%s]", AGENT_LOGIN_FILE);
                return NULL ;
        }
        if (trace_me) iniparser_dump(ini, stdout);

	sprintf(sec_name_cmp, "LOGIN_%s", templ);

        sec_count = iniparser_getnsec  (ini);

        for ( i = 0; i < sec_count; i++ ) {
                sec_name = iniparser_getsecname (ini, i);
#if 1
                if      (strncasecmp ( sec_name , sec_name_cmp, strlen(sec_name)) != 0)
#else
                if      (strnicmp ( sec_name , sec_name_cmp, strlen(sec_name)) != 0)
#endif
                        continue;
			
		sprintf(sec_attr, "%s:LOGIN", sec_name);
                login = strdup(iniparser_getstr(ini, sec_attr));

	}

	iniparser_freedict(ini);
	return login;
}



/*------------------------------------------------------------------*/
/*  parse_ini_file						    */
/*------------------------------------------------------------------*/

int parse_ini_file(char *ini_name, AlMoniHandle_T **MoniHandle, int *NrOfMoniTempl,  ez_cfg_t *ez_cfg, int *NrOfCfgs) {
	dictionary	*ini ;
	char 	 *s,
		 *moni_set,
		 *sec_name;

	int sec_count,
		i, j;
	char sec_attr [255];

	ez_cfg_t *ez;
        char pattern[AL_MONI_MAX_PATTERN_LENGTH];
        char *system,
             *appl,
             *value;


	*NrOfMoniTempl = 0;

	ini = iniparser_load(ini_name);
	if (ini==NULL) {
		fprintf(stderr, "cannot parse file [%s]", ini_name);
		return AG_CALL_INVALID ;
	}
	if (trace_me) iniparser_dump(ini, stdout);

	
	sec_count = iniparser_getnsec  (ini);
	MoniTempl =  (AlMoniTemplate_T*) malloc( sec_count * sizeof(AlMoniTemplate_T) );
	//*MoniTempl = (AlMoniTemplate_T*) calloc( sec_count , sizeof(AlMoniTemplate_T) );
	MoniHandles = (AlMoniHandle_T*) malloc ( sec_count * sizeof(AlMoniHandle_T));
	
	if (MoniTempl == NULL || MoniHandles == NULL )
		return AG_CALL_INVALID;


	for ( i = 0; i < sec_count; i++ ) {
		sec_name = iniparser_getsecname (ini, i);
#if 1
		if 	(strncasecmp ( sec_name , SECTION_NAME, strlen(SECTION_NAME)) != 0) 
#else
		if 	(strnicmp ( sec_name , SECTION_NAME, strlen(SECTION_NAME)) != 0) 
#endif
			continue;

		/* Template Name */
		strncpy(MoniTempl[*NrOfMoniTempl].TemplateName, (sec_name+ strlen(SECTION_NAME)) ,AL_MONI_MAX_TEMPL_NAME_LENGTH);
	
		/* Get the attributes  of section */	
		sprintf(sec_attr, "%s:MONI_SET_NAME", sec_name);
		moni_set = iniparser_getstr(ini, sec_attr);
		if (moni_set) {

			sprintf(sec_attr, "%s:MONI_NAME", sec_name);
			s = iniparser_getstr(ini, sec_attr);
			if (!s)
				return AG_TEMPLATE_ERROR;
		
			/* the obligatory attributes are set now*/
			strncpy(MoniTempl[*NrOfMoniTempl].MoniSetName, moni_set, AL_MONI_SET_NAME_LENGHT);
			MoniTempl[*NrOfMoniTempl].MoniSetName[AL_MONI_SET_NAME_LENGHT] = '\0';
			strncpy(MoniTempl[*NrOfMoniTempl].MoniName, s, AL_MONI_NAME_LENGHT);
			MoniTempl[*NrOfMoniTempl].MoniName[AL_MONI_NAME_LENGHT] = '\0';

			sprintf(sec_attr, "%s:MAX_TREE_DEPTH", sec_name);
			MoniTempl[*NrOfMoniTempl].MaxTreeDepth = iniparser_getint(ini, sec_attr, 0);


	               for (j = 0; j < AL_MONI_MAX_PATTERNS; j++) {
        	                sprintf(sec_attr, "%s:PATTERN_%d", sec_name, j);
                	        s = iniparser_getstr(ini, sec_attr);
	                        if (s) {
        	                        strncpy(MoniTempl[*NrOfMoniTempl].Pattern[MoniTempl[*NrOfMoniTempl].NumberOfPatterns], s, AL_MONI_MAX_PATTERN_LENGTH);
	                                MoniTempl[*NrOfMoniTempl].Pattern[MoniTempl[*NrOfMoniTempl].NumberOfPatterns][AL_MONI_MAX_PATTERN_LENGTH] = '\0';
	                                MoniTempl[*NrOfMoniTempl].NumberOfPatterns++;
        	                }
                	}
		} else {
	                /* Get the attributes  of section */
	                sprintf(sec_attr, "%s:SYSTEM", sec_name);
        	        system = iniparser_getstr(ini, sec_attr);
                	if (!system)
                	        system="*";

                	sprintf(sec_attr, "%s:APPL-SERVER", sec_name);
                	appl = iniparser_getstr(ini, sec_attr);
                	if (!appl)
                        	appl="*";

	                sprintf(sec_attr, "%s:VALUE", sec_name);
        	        value = iniparser_getstr(ini, sec_attr);
                	if (!value)
                        	return AG_TEMPLATE_ERROR;

			ez = get_cfg_template( ez_cfg, *NrOfCfgs, value);
			if (ez == NULL) {
				return AG_TEMPLATE_ERROR;
			}

			strncpy(MoniTempl[*NrOfMoniTempl].MoniSetName, ez->MoniSetName, AL_MONI_SET_NAME_LENGHT);
                        MoniTempl[*NrOfMoniTempl].MoniSetName[AL_MONI_SET_NAME_LENGHT] = '\0';
                        strncpy(MoniTempl[*NrOfMoniTempl].MoniName, ez->MoniName, AL_MONI_NAME_LENGHT);
                        MoniTempl[*NrOfMoniTempl].MoniName[AL_MONI_NAME_LENGHT] = '\0';

                        sprintf(sec_attr, "%s:MAX_TREE_DEPTH", sec_name);
                        MoniTempl[*NrOfMoniTempl].MaxTreeDepth = 0;

                	snprintf(pattern, AL_MONI_MAX_PATTERN_LENGTH, "%s\\%s\\%s", system, appl, ez->Pattern);
			strncpy(MoniTempl[*NrOfMoniTempl].Pattern[0], pattern,  AL_MONI_MAX_PATTERN_LENGTH);
			MoniTempl[*NrOfMoniTempl].Pattern[MoniTempl[*NrOfMoniTempl].NumberOfPatterns][AL_MONI_MAX_PATTERN_LENGTH] = '\0';
                        MoniTempl[*NrOfMoniTempl].NumberOfPatterns++ ;

		}

		/*** */
		sprintf(sec_attr, "%s:DESCRIPTION", sec_name);
		s = iniparser_getstr(ini, sec_attr);
                if (s) {
                	strncpy(MoniTempl[*NrOfMoniTempl].Description, s, AL_MONI_MAX_DESCRIPTION_LENGTH);
		} else {
		 	snprintf(MoniTempl[*NrOfMoniTempl].Description, AL_MONI_MAX_DESCRIPTION_LENGTH,
				 "%s: %s ",  MoniTempl[*NrOfMoniTempl].MoniSetName, MoniTempl[*NrOfMoniTempl].MoniName);	
		}
		/* Handle */
		MoniHandles[*NrOfMoniTempl] = &(MoniTempl[*NrOfMoniTempl]);
                
		/* Create Itab */
                MoniTempl[*NrOfMoniTempl].TreeNodes 	= ItCreate("TREE_NODES",sizeof( BAPITNDEXT),0,0);
		MoniTempl[*NrOfMoniTempl].TreeNodeValues = ItCreate("TREE_NODE_VALUES",sizeof( char[AL_MONI_MAX_TEXT_LENGTH]),0,0);

		// No Pattern-Information --> show everything
		if (MoniTempl[*NrOfMoniTempl].NumberOfPatterns == 0) {
			strncpy(MoniTempl[*NrOfMoniTempl].Pattern[0], "*", AL_MONI_MAX_PATTERN_LENGTH);
			MoniTempl[*NrOfMoniTempl].NumberOfPatterns++;
		}

		(*NrOfMoniTempl)++ ;
	}
 
	iniparser_freedict(ini);
	// If a template was not valid:
	MoniTempl = realloc(MoniTempl, (*NrOfMoniTempl) * sizeof(AlMoniTemplate_T));
	MoniHandles = realloc(MoniHandles, (*NrOfMoniTempl) * sizeof(AlMoniHandle_T));

	*MoniHandle = MoniHandles;
	return SAP_OK ;
}

/*------------------------------------------------------------------*/
/*   Init easy Configuration                                        */
/*------------------------------------------------------------------*/
int init_ez_cfg (ez_cfg_t *ez_cfg, int *NrOfCfgs) {
        FILE *fp;
        char buffer[512];
        char *s;

        fp = fopen(AG_EZ_FILE, "r");
	if (fp == NULL)
		return SAP_OK;

        while(fgets(buffer, sizeof(buffer), fp) != NULL) {
                if  (*NrOfCfgs < AG_MAX_EZ_CFGS) {
                        s =  strtok(buffer, "#");
                        if (s == NULL) return  AG_EZ_CFG_FILE_ERROR;
                        strcpy(ez_cfg[*NrOfCfgs].Name, s);

                        s =  strtok(NULL, "#");
                        if (s == NULL) return  AG_EZ_CFG_FILE_ERROR;
                        strcpy(ez_cfg[*NrOfCfgs].MoniSetName, s);

                        s =  strtok(NULL, "#");
                        if (s == NULL) return  AG_EZ_CFG_FILE_ERROR;
                        strcpy(ez_cfg[*NrOfCfgs].MoniName, s);

                        s =  strtok(NULL, "#");
                        if (s == NULL) return  AG_EZ_CFG_FILE_ERROR;
                        strcpy(ez_cfg[*NrOfCfgs].Pattern, s);

                        (*NrOfCfgs)++;
	          }
        }
        fclose(fp);
	return SAP_OK;
}

ez_cfg_t *  get_cfg_template( ez_cfg_t *ez_cfg, int NrOfCfgs, char *value) {
        int i;

        for (i = 0; i < NrOfCfgs; i++) {
                if (strcmp(value, ez_cfg[i].Name) == 0)
                        return &(ez_cfg[i]);
        }

        return NULL;
}

/*------------------------------------------------------------------*/
/*   Get Template for Handle	  			            */
/*------------------------------------------------------------------*/
AlMoniTemplate_T * get_template_by_handle (AlMoniHandle_T MoniHandle) {
	return MoniHandle;
}

/*------------------------------------------------------------------*/
/*   print_moni_templates	  			            */
/*------------------------------------------------------------------*/

void print_moni_templates (AlMoniHandle_T *MoniHandle, int NrOfMoniTempl) {
	AlMoniTemplate_T *MoniTemplates;
	int i,j;
	
	for (i = 0; i < NrOfMoniTempl; i++) {
		MoniTemplates = get_template_by_handle(MoniHandle[i]);
 
		printf("\nMONI_TEMPLATE %s\n", MoniTemplates->TemplateName);
		printf("MONI_DESCRIPTION %s\n", MoniTemplates->Description);
		printf("MONI_SET_NAME %s\n", MoniTemplates->MoniSetName);
		printf("MONI_NAME %s\n", MoniTemplates->MoniName);
		printf("MAX_TREE_DEPTH %d\n", MoniTemplates->MaxTreeDepth);

		for (j = 0; j < MoniTemplates->NumberOfPatterns; j++ ) {
			printf("PATTERN_%d: %s\n", j, MoniTemplates->Pattern[j]);
		}

		printf("------------------------------------------------\n");
	}

}

/*------------------------------------------------------------------*/
/*   sapmon_init	 					            */
/*------------------------------------------------------------------*/

int sapmon_init(AlMoniHandle_T **MoniHandle, int *NrOfMoniTempl) {
	int rc;
	int NrOfCfgs = 0;
	ez_cfg_t ez_cfg[AG_MAX_EZ_CFGS];

	trace_me = 0;

	rc = init_ez_cfg( ez_cfg, &NrOfCfgs);
	rc = parse_ini_file ( AGENT_INI_FILE, MoniHandle,  NrOfMoniTempl,  ez_cfg, &NrOfCfgs );
	if (trace_me) print_moni_templates ( *MoniHandle,   *NrOfMoniTempl);

	return rc;
}

void remove_trailing_blanks( char *s) {
	 char *stmp;
	 stmp = s + strlen(s);
	 while ( stmp-- != s && *stmp == ' ' ); 
	 *(stmp+1) = '\0';
}



/*--------------------------------------------------------------------*/
/* Filter_MTEs							      */
/*--------------------------------------------------------------------*/
int Filter_MTEs (AlMoniHandle_T MoniHandle ) {
	 AlMoniTemplate_T *MoniTemplates;
	int i;
	unsigned crow;
	BAPITNDEXT *tTreeNodes;
	char	 MTE_Name[AL_MTE_MAX_NAME];
	char	 buffer[AL_MTE_MAX_NAME];

	int	 matches_pattern;
	int 	 rc;


	MoniTemplates = get_template_by_handle(MoniHandle);

	/* No filter specified --> nothing to do
	   virtual and summary have to be sorted out
	
	for (i = 0;i < MoniTemplates->NumberOfPatterns; i++) {
		if (strcmp(MoniTemplates->Pattern[i], "*") == 0)
			return SAP_OK;
	}
	*/

        if (trace_me) printf("Filter %d MTEs\n",  ItFill(MoniTemplates->TreeNodes)) ;
	for (crow = 0;crow < ItFill( MoniTemplates->TreeNodes); crow++) {
		tTreeNodes = ItGetLine( MoniTemplates->TreeNodes,crow+1);		
	
		memset(MTE_Name, 0, sizeof(MTE_Name));	 
		memset(buffer  , 0, sizeof(buffer));	 
	
		strncpy(buffer, tTreeNodes->Mtsysid, 3 );
		remove_trailing_blanks(buffer);
		
		// virtual node? skip
		if( strcmp(buffer, "") != 0) {
		        strcat(MTE_Name, buffer);
			strcat(MTE_Name, "\\");
		} else {
		        rc = ItDelLine( MoniTemplates->TreeNodes, crow +1);
			crow--;
		        continue;
		}

		strncat(MTE_Name, tTreeNodes->Mtmcname, 40);
		remove_trailing_blanks(MTE_Name);
		strcat(MTE_Name, "\\");
		
		strncpy(buffer, tTreeNodes->Objectname, 40);
		remove_trailing_blanks(buffer);

		if( strcmp(buffer, "") != 0) {
                        strcat(MTE_Name, buffer);
                        strcat(MTE_Name, "\\");
                } else {
			//Summary Node!!!
			 rc = ItDelLine( MoniTemplates->TreeNodes, crow +1);
                        crow--;
			continue;
                }

		// MO
		if ( strncmp( buffer,  tTreeNodes->Mtnameshrt, strlen(buffer)) == 0) {
			if (trace_me)	printf("MO\n");
		} else {
			strncat(MTE_Name, tTreeNodes->Mtnameshrt, 40);
			remove_trailing_blanks(MTE_Name);
		}

		matches_pattern = 0;
		for (i = 0; i < MoniTemplates->NumberOfPatterns; i++) {
			if ( AlWildcardfit(MoniTemplates->Pattern[i] , MTE_Name)) {
				matches_pattern = 1;
				if (trace_me) printf("Matches: %s\n",MTE_Name) ;
				break;
			}
		}
	
		if (!matches_pattern) {
			 rc = ItDelLine( MoniTemplates->TreeNodes, crow +1);
			 crow--;	
		}
	}

	return 0;
}



/*--------------------------------------------------------------------*/
/* Get Tree Information 		                              */
/*--------------------------------------------------------------------*/
int sapmon_request_tree(AlMoniHandle_T MoniHandle, AlMoniNode_T **nodes, unsigned int *NrOfNodes){
	AlMoniTemplate_T *MoniTemplates;	
        int i;
        unsigned crow;
        BAPITNDEXT *tTreeNodes;

	if (trace_me) printf("sapmon_request_tree\n") ;
	
	MoniTemplates = get_template_by_handle(MoniHandle);

	*NrOfNodes =  ItFill( MoniTemplates->TreeNodes);
	
	*nodes = (AlMoniNode_T*) malloc ( *NrOfNodes * sizeof(AlMoniNode_T));
	

        for (crow = 0;crow < *NrOfNodes; crow++) {
                tTreeNodes = ItGetLine( MoniTemplates->TreeNodes,crow+1);

		strncpy((*nodes)[crow].Mtsysid, tTreeNodes->Mtsysid, MT_SYSID_LENGTH);
		(*nodes)[crow].Mtsysid[MT_SYSID_LENGTH] = '\0';				
		remove_trailing_blanks((*nodes)[crow].Mtsysid);	
	
		strncpy((*nodes)[crow].Mtmcname, tTreeNodes->Mtmcname, MT_MCNAME_LENGTH);
		(*nodes)[crow].Mtmcname[MT_MCNAME_LENGTH] = '\0';				
		remove_trailing_blanks((*nodes)[crow].Mtmcname);	
		
 		strncpy((*nodes)[crow].Objectname, tTreeNodes->Objectname, OBJECTNAME_LENGTH);
		(*nodes)[crow].Objectname[OBJECTNAME_LENGTH] = '\0';				
		remove_trailing_blanks((*nodes)[crow].Objectname);	
		
		strncpy((*nodes)[crow].Mtnameshrt, tTreeNodes->Mtnameshrt, MT_NAMESHRT_LENGTH);
		(*nodes)[crow].Mtnameshrt[MT_NAMESHRT_LENGTH] = '\0';				
		remove_trailing_blanks((*nodes)[crow].Mtnameshrt);	
		
	
		strncpy((*nodes)[crow].Alertdate, tTreeNodes->Alertdate, MT_DATE_LENGTH);
		(*nodes)[crow].Alertdate[MT_DATE_LENGTH] = '\0';				
		
		strncpy((*nodes)[crow].Alerttime, tTreeNodes->Alerttime, MT_TIME_LENGTH);
		(*nodes)[crow].Alerttime[MT_TIME_LENGTH] = '\0';				

	
		strncpy((*nodes)[crow].Lastvaldat, tTreeNodes->Lastvaldat, MT_DATE_LENGTH);
		(*nodes)[crow].Lastvaldat[MT_DATE_LENGTH] = '\0';				
		
		strncpy((*nodes)[crow].Lastvaltim, tTreeNodes->Lastvaltim, MT_TIME_LENGTH);
		(*nodes)[crow].Lastvaltim[MT_TIME_LENGTH] = '\0';				
		
		(*nodes)[crow].Actualval = tTreeNodes->Actualval;
		(*nodes)[crow].Actualsev = tTreeNodes->Actualsev;


		strncpy((*nodes)[crow].currentValue, ItGetLine(MoniTemplates->TreeNodeValues,crow+1), AL_MONI_MAX_TEXT_LENGTH-1);
		(*nodes)[crow].currentValue[AL_MONI_MAX_TEXT_LENGTH-1] = '\0';				
		remove_trailing_blanks((*nodes)[crow].currentValue);	
		
	}	

	return SAP_OK;
}

/*--------------------------------------------------------------------*/
/* Get Description                                                    */
/*--------------------------------------------------------------------*/
char *  sapmon_get_template_description (AlMoniHandle_T MoniHandle ) {
        AlMoniTemplate_T *MoniTemplates;

        MoniTemplates = get_template_by_handle(MoniHandle);
	if (trace_me) printf("sapmon_get_template_description \n") ;
	
	return MoniTemplates->Description;

}

/*--------------------------------------------------------------------*/
/* Get Template Name                                                  */
/*--------------------------------------------------------------------*/
char *  sapmon_get_template_name (AlMoniHandle_T MoniHandle ) {
        AlMoniTemplate_T *MoniTemplates;

        MoniTemplates = get_template_by_handle(MoniHandle);
        if (trace_me) printf("sapmon_get_template_name \n") ;

        return MoniTemplates->TemplateName;

}

/*--------------------------------------------------------------------*/
/* Start SAP ssh			                              */
/*--------------------------------------------------------------------*/
int sapmon_sap_start_ssh (char *sid, char *hostname, char *nr) {
	char command[255];

	sprintf(command, "ssh %sadm@%s startsap_%s_%s", strlwc(sid), hostname, hostname, nr);	
	return system(command);
}


/*--------------------------------------------------------------------*/
/* Stop SAP ssh				                              */
/*--------------------------------------------------------------------*/
int sapmon_sap_stop_ssh (char *sid, char *hostname, char *nr) {
        char command[255];

        sprintf(command, "ssh %sadm@%s stopsap_%s_%s", strlwc(sid), hostname, hostname, nr);
        return system(command);
}

/*--------------------------------------------------------------------*/
/* Start SAP 	                                                      */
/*--------------------------------------------------------------------*/
int sapmon_sap_start (char *sid, char *hostname, char *nr) {
        char command[255];

        sprintf(command, "su - %sadm -c  startsap_%s_%s",strlwc(sid),  hostname, nr);
        return system(command);
}
/*--------------------------------------------------------------------*/
/* Stop SAP                                                           */
/*--------------------------------------------------------------------*/
int sapmon_sap_stop (char *sid, char *hostname, char *nr) {
        char command[255];

        sprintf(command, "su - %sadm -c  stopsap_%s_%s",strlwc(sid),  hostname, nr);
        return system(command);

}


/*------------------------------------------------------------------*/
/*   Implementation of the UN*X wildcards in C. So they are         */
/*   available in a portable way and can be used whereever          */
/*   needed.                                                        */
/*------------------------------------------------------------------*/

static int set (char **wildcard, char **test);
/* Scans a set of characters and returns 0 if the set mismatches at this */
/* position in the teststring and 1 if it is matching                    */
/* wildcard is set to the closing ] and test is unmodified if mismatched */
/* and otherwise the char pointer is pointing to the next character      */

static int asterisk (char **wildcard, char **test);
/* scans an asterisk */

int AlWildcardfit (char *wildcard, char *test) {
  int fit = 1;
  
  for (; ('\000' != *wildcard) && (1 == fit) && ('\000' != *test); wildcard++) {
      switch (*wildcard)  {
        case '[':
		  wildcard++; /* leave out the opening square bracket */ 
          fit = set (&wildcard, &test);
	  /* we don't need to decrement the wildcard as in case */
	  /* of asterisk because the closing ] is still there */
          break;
        case '?':
          test++;
          break;
        case '*':
          fit = asterisk (&wildcard, &test);
	  /* the asterisk was skipped by asterisk() but the loop will */
	  /* increment by itself. So we have to decrement */
		  wildcard--;
          break;
        default:
          fit = (int) (*wildcard == *test);
          test++;
        }
    }
  while ((*wildcard == '*') && (1 == fit)) 
    /* here the teststring is empty otherwise you cannot */
    /* leave the previous loop */ 
    wildcard++;
  return (int) ((1 == fit) && ('\0' == *test) && ('\0' == *wildcard));
}

static int set (char **wildcard, char **test) {
  int fit = 0;
  int negation = 0;
  int at_beginning = 1;

  if ('!' == **wildcard) {
      negation = 1;
      (*wildcard)++;
  }
  while ((']' != **wildcard) || (1 == at_beginning)) {
      if (0 == fit) {
          if (('-' == **wildcard) 
              && ((*(*wildcard - 1)) < (*(*wildcard + 1)))
              && (']' != *(*wildcard + 1))
			  && (0 == at_beginning)) {
              
			  if (((**test) >= (*(*wildcard - 1)))
                  && ((**test) <= (*(*wildcard + 1)))) {
                  fit = 1;
                  (*wildcard)++;
              }
          } else if ((**wildcard) == (**test)) {
              fit = 1;
          }
      }
      (*wildcard)++;
      at_beginning = 0;
  }
  if (1 == negation)
    /* change from zero to one and vice versa */
    fit = 1 - fit;
  if (1 == fit) 
    (*test)++;

  return (fit);
}

static int asterisk (char **wildcard, char **test) {
  /* Warning: uses multiple returns */
  int fit = 1;

  /* erase the leading asterisk */
  (*wildcard)++; 
  while (('\000' != (**test))
	 && (('?' == **wildcard) 
	     || ('*' == **wildcard)))
    {
      if ('?' == **wildcard) 
	(*test)++;
      (*wildcard)++;
    }
  /* Now it could be that test is empty and wildcard contains */
  /* aterisks. Then we delete them to get a proper state */
  while ('*' == (**wildcard))
    (*wildcard)++;

  if (('\0' == (**test)) && ('\0' != (**wildcard)))
    return (fit = 0);
  if (('\0' == (**test)) && ('\0' == (**wildcard)))
    return (fit = 1); 
  else {
      /* Neither test nor wildcard are empty!          */
      /* the first character of wildcard isn't in [*?] */
      if (0 == AlWildcardfit(*wildcard, (*test))) {
		do {
	      (*test)++;
	      /* skip as much characters as possible in the teststring */
	      /* stop if a character match occurs */
	      while (((**wildcard) != (**test)) 
		     && ('['  != (**wildcard))
		     && ('\0' != (**test)))
			(*test)++;
	    }
	    
		 while ((('\0' != **test))? 
		 (0 == AlWildcardfit (*wildcard, (*test))) 
		 : (0 != (fit = 0)));
	  }
      if (('\0' == **test) && ('\0' == **wildcard))
		fit = 1;
      return (fit);
   }
}
/*******************************/
/* Wildcard-Function ends here */
/*******************************/
