示例#1
0
/*
 * comprueba si la secuencia identificadores de elemento
 * concuerda con la regla de tipo 'child' dada por el
 * puntero.
 *
 * la secuencia 'elements' es un array de identificadores ordenada
 * el número de elementos del array lo indica 'num'
 * el puntero a la regla es 'rule_ptr'
 *
 * DEVUELVE: 1 si lo es o 0 si no lo es (-1 si lo podría ser con
 *                más elementos)
 *
 */
int dtd_is_child_valid(int rule_ptr, int elements[], int num)
{
  int rule;
  int valid;

  DEBUG("dtd_is_child_valid()");

  rule= rule_ptr;
  valid=is_child_valid(&rule, elements, num);

  EPRINTF2("   código retornado: %d [regla %d]\n",valid,rule);

  if (valid==num) return 1;
  else if (valid==-2) return -1; /* no válido, pero por falta de elm */

  /* no válido */
  else return 0;
}
示例#2
0
/*
 *
 * función recursiva en la que se basa el funcionamiento de 
 * dtd_is_child_valid()
 *
 * devuelve: <0:  no es válido
 *           num: es válido con 'num' elementos coincidentes 
 *
 */
static int is_child_valid(int *rule_ptr, int elements[], int num)
{
  unsigned char data;
  int is_choice;
  int repeat;
  int rule;
  int elm;
  int valid = -1;
  int elm_matched;
  int error_code;
  int coincide_choice;

#ifdef CHILD_DEBUG
  char str[1024];
  int len_buff= 0;
  int i;
#endif

  DEBUG("is_child_valid()");

#ifdef CHILD_DEBUG
  EPRINTF2("    rule: %d; num: %d;\n", *rule_ptr, num);
  EPRINTF1("    %s\n", contentspecToString(&elm_buffer[*rule_ptr], str, 
					 CONTTYPE_CHILDREN, &len_buff));
  EPRINTF("    :: ");  
  for (i=0; i<num; i++)
    EPRINTF1("%s ", elm_list[elements[i]].name);
  EPRINTF("\n");
#endif

  coincide_choice= 0;
  error_code= -1;
  rule= *rule_ptr;
  data= elm_buffer[rule];

  if (!CSPEC_ISPAR(data) || (!(data & CSPEC_PAR_O)))
    EXIT("dtd_is_child_valid ¡la regla no empieza con '('!");

  is_choice= CSPEC_ISCHOICE(data);
  repeat= CSPEC_NUM(data);

#ifdef CHILD_DEBUG
  if (is_choice) EPRINTF("    | ");
  else EPRINTF("    , ");
  switch (repeat) {
  case CSPEC_AST:
    EPRINTF("*\n");
    break;
  case CSPEC_MAS:
    EPRINTF("+\n");
    break;
  case CSPEC_INT:
    EPRINTF("?\n");
    break;
  default:
    EPRINTF("1\n");
    break;
  }
#endif

  elm= 0;
  elm_matched= 0;
  data= elm_buffer[++rule];
  for ( ; ; data= elm_buffer[++rule]) {

    /* mira si es válido el elemento actual */
    if (CSPEC_ISELM(data)) {
      /* es un elemento suelto */
      if ((elm<num) && elements[elm]==CSPEC_ELM(data)) valid= 1;
      else if (elm>=num) valid=-2; /* faltan elementos */
      else valid= -1;
#ifdef CHILD_DEBUG
      EPRINTF3("    .    [%d:%d] %s\n",rule,valid,elm_list[CSPEC_ELM(data)].name);
#endif

    } else if (data & CSPEC_PAR_O) {
      /* es una regla compuesta: comienza con '(' */
#ifdef CHILD_DEBUG
      int rule0= rule;
      EPRINTF1("    >>   [%d]\n",rule);
#endif
      valid= is_child_valid(&rule, elements+elm, num-elm);
#ifdef CHILD_DEBUG
      EPRINTF3("    <<   [%d:%d] %s\n",rule,valid,
	       contentspecToString(&elm_buffer[rule0], str, 
				   CONTTYPE_CHILDREN, &len_buff));
      EPRINTF1("         -> %s\n",
	       contentspecToString(&elm_buffer[rule+1], str, 
				   CONTTYPE_CHILDREN, &len_buff));
#endif
   
    } else if (data & CSPEC_PAR_C) {
      /* fin de esta regla */

#ifdef CHILD_DEBUG
      EPRINTF2("    ))   coincide_choice:%d; elm_matched:%d\n",
	       coincide_choice, elm_matched);
#endif

      if (is_choice) {
	/* error si no hubo coincidencias en iteraciones anteriores
         * y el tipo no permite 0 coincidencias
	 */
	*rule_ptr= rule;
	if ((coincide_choice)||(elm_matched>0)
	    ||(repeat==CSPEC_INT)||(repeat==CSPEC_AST)) 
	  return elm_matched;
	else return error_code;	
      } else {
	/* si no es choice, se cumple */
	elm_matched= elm;
	
	/* retorna si sólo permite una coincidenecia */
	if ((repeat==CSPEC_INT)||(repeat==0)) {
	  *rule_ptr= rule;
	  return elm_matched;
	} else {
	  /* vuelve a verificar */
	  rule= *rule_ptr;
#ifdef CHILD_DEBUG
      EPRINTF("    --R--\n");
#endif
	  continue;
	}
      }
    } else EXIT("is_child_valid ¡regla incorrecta!");



    /* comprueba el resultado de este elemento */
    if (valid>=0) {

#ifdef CHILD_DEBUG
      EPRINTF1("    --V-- %d\n", valid);
#endif

      /* OK, se mira el siguiente elemento (si no es CHOICE) o se finaliza */
      elm+= valid;

      /* si es choice, busca el fin y retorna */
      if (is_choice) {
	elm_matched= elm;
	coincide_choice= 1;

	/* si no se emparejó ninguno, 
	 * aunque sea válido, se continúa con el siguiente */
	if (elm_matched) {
	  /* si es '*' o '+', o continúa el bucle */
	  if ((!repeat)||(repeat==CSPEC_INT)) {
	    rule= search_par_close(rule+1);
	    *rule_ptr= rule;
	    return elm;
	  }
	  else rule= *rule_ptr;
	}
      }
      
      /* no es choice,
       * o es choice válido sin emparejar ningún elemento
       * ==> se mira si cumple el siguiente elemento 
       */

    } else {
      /* no válido */
      /* si no es choice retorna con error */

#ifdef CHILD_DEBUG
      EPRINTF1("    --NV-- %d\n", valid);
#endif

      if (!is_choice) {
	rule= search_par_close(rule+1);
	*rule_ptr= rule;

	/* error si no hubo coincidencias en iteraciones anteriores
         * y el tipo no permite 0 coincidencias
	 */
	if ((elm_matched>0)||(repeat==CSPEC_INT)||(repeat==CSPEC_AST)) 
	  return elm_matched;    /* no hay error */
	else return valid;       /* hay error */
      }

      /* es choice, se sigue probando */
      if (valid==-2) error_code= -2;
    }
  } /* for */

}
/*
 * fas_call_pkt_comp does sanity checking to ensure that we don't
 * call completion twice on the same packet or a packet that has been freed.
 * if there is a completion function specified, the packet is queued
 * up and it is left to the fas_callback thread to empty the queue at
 * a lower priority; note that there is one callback queue per fas
 *
 * we use a separate thread for calling back into the target driver
 * this thread unqueues packets from the callback queue
 */
void
fas_call_pkt_comp(register struct fas *fas, register struct fas_cmd *sp)
{
	TRACE_0(TR_FAC_SCSI, TR_FAS_CALL_PKT_COMP_START,
	    "fas_call_pkt_comp_start");

	ASSERT(sp != 0);
	ASSERT((sp->cmd_flags & CFLAG_COMPLETED) == 0);
	ASSERT((sp->cmd_flags & CFLAG_FREE) == 0);
	ASSERT(sp->cmd_flags & CFLAG_FINISHED);
	ASSERT(fas->f_ncmds >= fas->f_ndisc);
	ASSERT((sp->cmd_flags & CFLAG_CMDDISC) == 0);
	ASSERT(sp != fas->f_current_sp);
	ASSERT(sp != fas->f_active[sp->cmd_slot]->f_slot[sp->cmd_tag[1]]);

	sp->cmd_flags &= ~CFLAG_IN_TRANSPORT;
	sp->cmd_flags |= CFLAG_COMPLETED;
	sp->cmd_qfull_retries = 0;

	/*
	 * if this was an auto request sense, complete immediately to free
	 * the arq pkt
	 */
	if (sp->cmd_pkt->pkt_comp && !(sp->cmd_flags & CFLAG_CMDARQ)) {

		if (sp->cmd_pkt->pkt_reason != CMD_CMPLT) {
			IPRINTF6("completion for %d.%d, sp=0x%p, "
			    "reason=%s, stats=%x, state=%x\n",
				Tgt(sp), Lun(sp), (void *)sp,
				scsi_rname(sp->cmd_pkt->pkt_reason),
				sp->cmd_pkt->pkt_statistics,
				sp->cmd_pkt->pkt_state);
		} else {
			EPRINTF2("completion queued for %d.%dn",
				Tgt(sp), Lun(sp));
		}

		/*
		 * append the packet or start a new queue
		 */
		mutex_enter(&fas->f_c_mutex);
		if (fas->f_c_qf) {
			/*
			 * add to tail
			 */
			register struct fas_cmd *dp = fas->f_c_qb;
			ASSERT(dp != NULL);
			fas->f_c_qb =	sp;
			sp->cmd_forw = NULL;
			dp->cmd_forw = sp;
		} else {
			/*
			 * start new queue
			 */
			fas->f_c_qf = fas->f_c_qb = sp;
			sp->cmd_forw = NULL;
		}
		mutex_exit(&fas->f_c_mutex);

	} else if ((sp->cmd_flags & CFLAG_CMDARQ) && sp->cmd_pkt->pkt_comp) {
		/*
		 * pkt_comp may be NULL when we are aborting/resetting but then
		 * the callback will be redone later
		 */
		fas_complete_arq_pkt(sp->cmd_pkt);

	} else	{
		EPRINTF2("No completion routine for 0x%p reason %x\n",
		    (void *)sp, sp->cmd_pkt->pkt_reason);
	}
	TRACE_0(TR_FAC_SCSI, TR_FAS_CALL_PKT_COMP_END,
	    "fas_call_pkt_comp_end");
}