Esempio n. 1
0
File: tags.c Progetto: dacap/htmlex
static char *tag_macro (int argc, char *argv[])
{
  if (argc >= 1) {
    if (argc >= 2) {
      char *value = process_text (argv[1]);
      MACRO *macro = get_macro (macros_space[0], argv[0]);

      /* modify macro */
      if (macro) {
	modify_macro (macro, value);
      }
      /* new macro */
      else {
	macro = new_macro (NORMAL_MACRO, strdup (argv[0]), value);
	add_macro (macros_space[0], macro, TRUE);
      }
    }
    else {
      /* remove macro */
      remove_macro (macros_space[0], argv[0]);
    }
  }

  return NULL;
}
Esempio n. 2
0
/****************************************************************
 * mdsdcl_define:
 * Define an mds macro ...
 ****************************************************************/
int   mdsdcl_define()			/* Return: status		*/
{
    int   i,k;
    int   sts;
    char  name[32];
    char  *p;
    struct _mdsdcl_macro  *m;
    static DYNAMIC_DESCRIPTOR(dsc_name);
    static DYNAMIC_DESCRIPTOR(dsc_cmd);
    static char  fmt1[] = "Macro '%s' is open -- cannot be edited";

    sts = cli_get_value("P1",&dsc_name);
    if (~sts & 1)
        return(sts);

    k = dsc_name.dscW_length;
    if (k >= sizeof(name))
        k = sizeof(name) - 1;
    l2un(name,dsc_name.dscA_pointer,k);
    name[k] = '\0';

    /*=======================================================
     * Get addr of macro struct.  Delete any existing lines ...
     *======================================================*/
    m = get_macro(name);
    if (m->isOpen)
        return(MdsMsg(MDSDCL_STS_ERROR,fmt1,m->name));

    for (i=0 ; i<m->numLines ; i++)
        free(m->lines[i]);
    m->numLines = 0;

    /*======================================================
     * Read new macro from input ...
     *=====================================================*/
    for ( ; (sts = mdsdcl_get_input_nosymbols("DEFMAC> ",&dsc_cmd)) & 1 ; )
    {
        if ((dsc_cmd.dscW_length > 0) && dsc_cmd.dscA_pointer)
            p = nonblank(dsc_cmd.dscA_pointer);
        else
            p = 0;
        if (!p || end_macro(p))
        {
            break;
        }
        if (m->numLines >= m->maxLines)
            extend_macro(m);
        m->lines[m->numLines++] = STRING_ALLOC(dsc_cmd.dscA_pointer);
    }
    return(1);
}
Esempio n. 3
0
File: macro.c Progetto: mnemnion/imp
int read_macro(struct prog_info *pi, char *name) 
{
	int loopok;
    int i;
    int start;
	struct macro *macro;
	struct macro_line *macro_line;
    struct macro_line **last_macro_line = NULL;
	struct macro_label *macro_label;

	if(pi->pass == PASS_1) {
		if(!name) {
			print_msg(pi, MSGTYPE_ERROR, "missing macro name");
			return(True);
		}
		get_next_token(name, TERM_END);

		for(i = 0; !IS_END_OR_COMMENT(name[i]); i++) {	
			if(!IS_LABEL(name[i])) {
				print_msg(pi, MSGTYPE_ERROR, "illegal characters used in macro name '%s'",name);
				return(False);
			}
		}

		macro = calloc(1, sizeof(struct macro));
		if(!macro) {
			print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
			return(False);
		}

  		if(pi->last_macro)
			pi->last_macro->next = macro;
		else
			pi->first_macro = macro;
		pi->last_macro = macro;
		macro->name = malloc(strlen(name) + 1);
		if(!macro->name) {
			print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
			return(False);
		}
		strcpy(macro->name, name);
		macro->include_file = pi->fi->include_file;
		macro->first_line_number = pi->fi->line_number;
		last_macro_line = &macro->first_macro_line;
	}
	else {  /* pi->pass == PASS_2 */
		if(pi->list_line && pi->list_on) {
			fprintf(pi->list_file, "          %s\n", pi->list_line);
			pi->list_line = NULL;
		}
		// reset macro label running numbers
		get_next_token(name, TERM_END);
		macro = get_macro(pi, name);
		if (!macro) {
			print_msg(pi, MSGTYPE_ERROR, "macro inconsistency in '%s'", name);
			return(True);
		}
		for(macro_label = macro->first_label; macro_label; macro_label = macro_label->next) {
			macro_label->running_number = 0;
		}
	}

	loopok = True;
	while(loopok) {
		if(fgets_new(pi,pi->fi->buff, LINEBUFFER_LENGTH, pi->fi->fp)) {
			pi->fi->line_number++;
			i = 0;
			while(IS_HOR_SPACE(pi->fi->buff[i]) && !IS_END_OR_COMMENT(pi->fi->buff[i])) i++;
			if(pi->fi->buff[i] == '.') {
			  i++;
			  if(!nocase_strncmp(&pi->fi->buff[i], "endm", 4))
				loopok = False;
			  if(!nocase_strncmp(&pi->fi->buff[i], "endmacro", 8))
				loopok = False;
			}
			if(pi->pass == PASS_1) {
				if(loopok) {
					i = 0; /* find start of line */
					while(IS_HOR_SPACE(pi->fi->buff[i]) && !IS_END_OR_COMMENT(pi->fi->buff[i])) {
     					i++;
					}
					start = i;
					/* find end of line */
					while(!IS_END_OR_COMMENT(pi->fi->buff[i]) && (IS_LABEL(pi->fi->buff[i]) || pi->fi->buff[i] == ':')) {
     					i++;
					}
					if(pi->fi->buff[i-1] == ':' && (pi->fi->buff[i-2] == '%' 
     					&& (IS_HOR_SPACE(pi->fi->buff[i]) || IS_END_OR_COMMENT(pi->fi->buff[i])))) {
						if(macro->first_label) {
							for(macro_label = macro->first_label; macro_label->next; macro_label=macro_label->next){}
             				macro_label->next = calloc(1,sizeof(struct macro_label));
             				macro_label = macro_label->next;
		   				}
         				else {
             				macro_label = calloc(1,sizeof(struct macro_label));
             				macro->first_label = macro_label;
                		}
                		macro_label->label = malloc(strlen(&pi->fi->buff[start])+1);
                		pi->fi->buff[i-1] = '\0';
           				strcpy(macro_label->label, &pi->fi->buff[start]);
                		pi->fi->buff[i-1] = ':';
           				macro_label->running_number = 0;
					}
				
					macro_line = calloc(1, sizeof(struct macro_line));
					if(!macro_line) {
						print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
						return(False);
					}
					*last_macro_line = macro_line;
					last_macro_line = &macro_line->next;
					macro_line->line = malloc(strlen(pi->fi->buff) + 1);
					if(!macro_line->line) {
						print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
						return(False);
					}
					strcpy(macro_line->line, &pi->fi->buff[start]);
				}
			}
			else if(pi->fi->buff && pi->list_file && pi->list_on) {
				if(pi->fi->buff[i] == ';')
					fprintf(pi->list_file, "         %s\n", pi->fi->buff);
				else
					fprintf(pi->list_file, "          %s\n", pi->fi->buff);
			}
		}
		else {
			if(feof(pi->fi->fp)) {
				print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDMACRO");
				return(True);
			}
			else {
				perror(pi->fi->include_file->name);
				return(False);
			}
		}
	}
	return(True);
}
Esempio n. 4
0
/*
 * We are guaranteed that the packet received is a BOOTP request packet,
 * e.g., *NOT* a DHCP packet.
 */
void
bootp(dsvc_clnt_t *pcd, PKT_LIST *plp)
{
	boolean_t	result, existing_offer = B_FALSE;
	int		err, write_error = DSVC_SUCCESS, flags = 0;
	int		pkt_len;
	uint_t		crecords = 0, irecords = 0, srecords = 0, clen;
	uint32_t	query;
	PKT		*rep_pktp = NULL;
	IF		*ifp = pcd->ifp;
	dsvc_dnet_t	*pnd = pcd->pnd;
	uchar_t		*optp;
	dn_rec_t	dn, ndn, *dnp;
	dn_rec_list_t	*dncp = NULL, *dnip = NULL, *dnlp = NULL;
	struct in_addr	ciaddr;
	struct in_addr	no_ip;	/* network order IP */
	ENCODE		*ecp, *hecp;
	MACRO		*mp, *nmp, *cmp;
	time_t		now = time(NULL);
	DHCP_MSG_CATEGORIES	log;
	struct		hostent	h, *hp;
	char		ntoab[INET_ADDRSTRLEN], cipbuf[INET_ADDRSTRLEN];
	char		cidbuf[DHCP_MAX_OPT_SIZE];
	char		hbuf[NSS_BUFLEN_HOSTS];

	ciaddr.s_addr = htonl(INADDR_ANY);

#ifdef	DEBUG
	dhcpmsg(LOG_DEBUG, "BOOTP request received on %s\n", ifp->nm);
#endif	/* DEBUG */

	if (pcd->off_ip.s_addr != htonl(INADDR_ANY) &&
	    PCD_OFFER_TIMEOUT(pcd, now))
		purge_offer(pcd, B_TRUE, B_TRUE);

	if (pcd->off_ip.s_addr != htonl(INADDR_ANY)) {
		existing_offer = B_TRUE;
		dnlp = pcd->dnlp;
		assert(dnlp != NULL);
		dnp = dnlp->dnl_rec;
		no_ip.s_addr = htonl(dnp->dn_cip.s_addr);
		crecords = 1;
	} else {
		/*
		 * Try to find a CID entry for the client. We don't care about
		 * lease info here, since a BOOTP client always has a permanent
		 * lease. We also don't care about the entry owner either,
		 * unless we end up allocating a new entry for the client.
		 */
		DSVC_QINIT(query);

		DSVC_QEQ(query, DN_QCID);
		(void) memcpy(dn.dn_cid, pcd->cid, pcd->cid_len);
		dn.dn_cid_len = pcd->cid_len;

		DSVC_QEQ(query, DN_QFBOOTP_ONLY);
		dn.dn_flags = DN_FBOOTP_ONLY;

		/*
		 * If a client address (ciaddr) is given, we simply trust that
		 * the client knows what it's doing, and we use that IP address
		 * to locate the client's record. If we can't find the client's
		 * record, then we keep silent. If the client id of the record
		 * doesn't match this client, then either the client or our
		 * database is inconsistent, and we'll ignore it (notice
		 * message generated).
		 */
		ciaddr.s_addr = plp->pkt->ciaddr.s_addr;
		if (ciaddr.s_addr != htonl(INADDR_ANY)) {
			DSVC_QEQ(query, DN_QCIP);
			dn.dn_cip.s_addr = ntohl(ciaddr.s_addr);
		}

		dnlp = dhcp_lookup_dd_classify(pcd->pnd, B_FALSE, query,
		    -1, &dn, (void **)&dncp, S_CID);
		if (dnlp != NULL) {
			crecords = 1;
			dnp = dnlp->dnl_rec;
			if (dnp->dn_flags & DN_FUNUSABLE)
				goto leave_bootp;
			no_ip.s_addr = htonl(dnp->dn_cip.s_addr);
		}
	}

	(void) inet_ntop(AF_INET, &no_ip, cipbuf, sizeof (cipbuf));

	if (crecords == 0 && !be_automatic) {
		if (verbose) {
			dhcpmsg(LOG_INFO, "BOOTP client: %1$s is looking for "
			    "a configuration on net %2$s\n", pcd->cidbuf,
			    pnd->network);
		}
		goto leave_bootp;
	}

	/*
	 * If the client thinks it knows who it is (ciaddr), and this doesn't
	 * match our registered IP address, then display an error message and
	 * give up.
	 */
	if (ciaddr.s_addr != htonl(INADDR_ANY) && crecords == 0) {
		/*
		 * If the client specified an IP address, then let's check
		 * whether it is available, since we have no CID mapping
		 * registered for this client. If it is available and
		 * unassigned but owned by a different server, we ignore the
		 * client.
		 */
		DSVC_QINIT(query);

		DSVC_QEQ(query, DN_QCIP);
		dn.dn_cip.s_addr = ntohl(ciaddr.s_addr);
		(void) inet_ntop(AF_INET, &ciaddr, cipbuf, sizeof (cipbuf));

		DSVC_QEQ(query, DN_QFBOOTP_ONLY);
		dn.dn_flags = DN_FBOOTP_ONLY;

		dnip = NULL;
		dnlp = dhcp_lookup_dd_classify(pcd->pnd, B_FALSE, query,
		    -1, &dn, (void **)&dncp, S_CID);
		if (dnlp == NULL) {
			/*
			 * We have no record of this client's IP address, thus
			 * we really can't respond to this client, because it
			 * doesn't have a configuration.
			 */
			if (verbose) {
				dhcpmsg(LOG_INFO, "No configuration for BOOTP "
				    "client: %1$s. IP address: %2$s not "
				    "administered by this server.\n",
				    pcd->cidbuf, inet_ntop(AF_INET, &ciaddr,
				    ntoab, sizeof (ntoab)));
			}
			goto leave_bootp;
		} else
			irecords = 1;

		dnp = dnlp->dnl_rec;
		if (dnp->dn_flags & DN_FUNUSABLE)
			goto leave_bootp;

		if (dn.dn_cid_len != 0) {
			if (dn.dn_cid_len != pcd->cid_len || memcmp(dn.dn_cid,
			    pcd->cid, pcd->cid_len) != 0) {
				if (verbose) {
					clen = sizeof (cidbuf);
					(void) octet_to_hexascii(dn.dn_cid,
					    dn.dn_cid_len, cidbuf, &clen);
					dhcpmsg(LOG_INFO, "BOOTP client: %1$s "
					    "thinks it owns %2$s, but that "
					    "address belongs to %3$s. Ignoring "
					    "client.\n", pcd->cidbuf, cipbuf,
					    cidbuf);
				}
				goto leave_bootp;
			}
		} else {
			if (match_ownerip(htonl(dn.dn_sip.s_addr)) == NULL) {
				if (verbose) {
					no_ip.s_addr =
					    htonl(dnp->dn_sip.s_addr);
					dhcpmsg(LOG_INFO, "BOOTP client: %1$s "
					    "believes it owns %2$s. That "
					    "address is free, but is owned by "
					    "DHCP server %3$s. Ignoring "
					    "client.\n", pcd->cidbuf, cipbuf,
					    inet_ntop(AF_INET, &no_ip, ntoab,
					    sizeof (ntoab)));
				}
				goto leave_bootp;
			}
		}
		no_ip.s_addr = htonl(dnp->dn_cip.s_addr);
		(void) inet_ntop(AF_INET, &no_ip, cipbuf, sizeof (cipbuf));
	}

	if (crecords == 0) {
		/*
		 * The dhcp-network table did not have any matching entries.
		 * Try to allocate a new one if possible.
		 */
		if (irecords == 0 && select_offer(pnd, plp, pcd, &dnlp)) {
			dnp = dnlp->dnl_rec;
			no_ip.s_addr = htonl(dnp->dn_cip.s_addr);
			(void) inet_ntop(AF_INET, &no_ip, cipbuf,
			    sizeof (cipbuf));
			srecords = 1;
		}
	}

	if (crecords == 0 && irecords == 0 && srecords == 0) {
		dhcpmsg(LOG_NOTICE,
		    "(%1$s) No more BOOTP IP addresses for %2$s network.\n",
		    pcd->cidbuf, pnd->network);
		goto leave_bootp;
	}

	/* Check the address. But only if client doesn't know its address. */
	ndn = *dnp;	/* struct copy */
	no_ip.s_addr = htonl(ndn.dn_cip.s_addr);
	(void) inet_ntop(AF_INET, &no_ip, cipbuf, sizeof (cipbuf));
	if (ciaddr.s_addr == htonl(INADDR_ANY)) {
		if ((ifp->flags & IFF_NOARP) == 0)
			(void) set_arp(ifp, &no_ip, NULL, 0, DHCP_ARP_DEL);
		if (!noping) {
			/*
			 * If icmp echo check fails,
			 * let the plp fall by the wayside.
			 */
			errno = icmp_echo_check(&no_ip, &result);
			if (errno != 0) {
				dhcpmsg(LOG_ERR, "ICMP ECHO check cannot be "
				    "performed for: %s, ignoring\n", cipbuf);
				goto leave_bootp;
			}
			if (result) {
				dhcpmsg(LOG_ERR, "ICMP ECHO reply to BOOTP "
				    "OFFER candidate: %s, disabling.\n",
				    cipbuf);

				ndn.dn_flags |= DN_FUNUSABLE;

				if ((err = dhcp_modify_dd_entry(pnd->dh,
				    dnp, &ndn)) == DSVC_SUCCESS) {
					/* Keep the cached entry current. */
					*dnp = ndn;    /* struct copy */
				}

				logtrans(P_BOOTP, L_ICMP_ECHO, 0, no_ip,
				    server_ip, plp);

				goto leave_bootp;
			}
		}
	}

	/*
	 * It is possible that the client could specify a REQUEST list,
	 * but then it would be a DHCP client, wouldn't it? Only copy the
	 * std option list, since that potentially could be changed by
	 * load_options().
	 */
	ecp = NULL;
	if (!no_dhcptab) {
		open_macros();
		if ((nmp = get_macro(pnd->network)) != NULL)
			ecp = dup_encode_list(nmp->head);
		if ((mp = get_macro(dnp->dn_macro)) != NULL)
			ecp = combine_encodes(ecp, mp->head, ENC_DONT_COPY);
		if ((cmp = get_macro(pcd->cidbuf)) != NULL)
			ecp = combine_encodes(ecp, cmp->head, ENC_DONT_COPY);

		/* If dhcptab configured to return hostname, do so. */
		if (find_encode(ecp, DSYM_INTERNAL, CD_BOOL_HOSTNAME) !=
		    NULL) {
			hp = gethostbyaddr_r((char *)&ndn.dn_cip,
			    sizeof (struct in_addr), AF_INET, &h, hbuf,
			    sizeof (hbuf), &err);
			if (hp != NULL) {
				hecp = make_encode(DSYM_STANDARD,
				    CD_HOSTNAME, strlen(hp->h_name),
				    hp->h_name, ENC_COPY);
				replace_encode(&ecp, hecp, ENC_DONT_COPY);
			}
		}
	}

	/* Produce a BOOTP reply. */
	rep_pktp = gen_bootp_pkt(sizeof (PKT), plp->pkt);

	rep_pktp->op = BOOTREPLY;
	optp = rep_pktp->options;

	/*
	 * Set the client's "your" IP address if client doesn't know it,
	 * otherwise echo the client's ciaddr back to him.
	 */
	if (ciaddr.s_addr == htonl(INADDR_ANY))
		rep_pktp->yiaddr.s_addr = htonl(ndn.dn_cip.s_addr);
	else
		rep_pktp->ciaddr.s_addr = ciaddr.s_addr;

	/*
	 * Omit lease time options implicitly, e.g.
	 * ~(DHCP_DHCP_CLNT | DHCP_SEND_LEASE)
	 */

	if (!plp->rfc1048)
		flags |= DHCP_NON_RFC1048;

	/* Now load in configured options. */
	pkt_len = load_options(flags, plp, rep_pktp, sizeof (PKT), optp, ecp,
	    NULL);

	free_encode_list(ecp);
	if (!no_dhcptab)
		close_macros();

	if (pkt_len < sizeof (PKT))
		pkt_len = sizeof (PKT);

	/*
	 * Only perform a write if we have selected an entry not yet
	 * assigned to the client (a matching DN_FBOOTP_ONLY entry from
	 * ip address lookup, or an unassigned entry from select_offer()).
	 */
	if (srecords > 0 || irecords > 0) {
		(void) memcpy(&ndn.dn_cid, pcd->cid, pcd->cid_len);
		ndn.dn_cid_len = pcd->cid_len;

		write_error = dhcp_modify_dd_entry(pnd->dh, dnp, &ndn);

		/* Keep state of the cached entry current. */
		*dnp = ndn;	/* struct copy */

		log = L_ASSIGN;
	} else {
		if (verbose) {
			dhcpmsg(LOG_INFO, "Database write unnecessary for "
			    "BOOTP client: %1$s, %2$s\n",
			    pcd->cidbuf, cipbuf);
		}
		log = L_REPLY;
	}

	if (write_error == DSVC_SUCCESS) {
		if (send_reply(ifp, rep_pktp, pkt_len, &no_ip) != 0) {
			dhcpmsg(LOG_ERR,
			    "Reply to BOOTP client %1$s with %2$s failed.\n",
			    pcd->cidbuf, cipbuf);
		} else {
			/* Note that the conversation has completed. */
			pcd->state = ACK;

			(void) update_offer(pcd, &dnlp, 0, &no_ip, B_TRUE);
			existing_offer = B_TRUE;
		}

		logtrans(P_BOOTP, log, ndn.dn_lease, no_ip, server_ip, plp);
	}

leave_bootp:
	if (rep_pktp != NULL)
		free(rep_pktp);
	if (dncp != NULL)
		dhcp_free_dd_list(pnd->dh, dncp);
	if (dnip != NULL)
		dhcp_free_dd_list(pnd->dh, dnip);
	if (dnlp != NULL && !existing_offer)
		dhcp_free_dd_list(pnd->dh, dnlp);
}
Esempio n. 5
0
File: macro.c Progetto: mnemnion/imp
int expand_macro(struct prog_info *pi, struct macro *macro, char *rest_line)
{
  int 	ok = True, macro_arg_count = 0, off, a, b = 0, c, i = 0, j = 0; 
  char 	*line = NULL;
  char  *temp;
  char  *macro_args[MAX_MACRO_ARGS];
  char  tmp[7];
  char 	buff[LINEBUFFER_LENGTH];
  char	arg = False; 
  char	*nmn; //string buffer for 'n'ew 'm'acro 'n'ame
  struct 	macro_line *old_macro_line;
  struct 	macro_call *macro_call;
  struct	macro_label *macro_label;

  if(rest_line) {
    //we reserve some extra space for extended macro parameters
    line = malloc(strlen(rest_line) + 20); 
 	if(!line) {
	  print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
	  return(False);
    }
		
	/* exchange amca word 'src' with YH:YL and 'dst' with ZH:ZL */
	for(c = 0, a = strlen(rest_line); c < a; c++) {
	  switch (tolower(rest_line[c])) {
		case 's':
          if(IS_SEPARATOR(rest_line[c-1]) && (rest_line[c+1] == 'r') && (rest_line[c+2] == 'c') && IS_SEPARATOR(rest_line[c+3])) {
            strcpy(&line[b],"YH:YL");
            b += 5;
            c += 2;
          }
          else {
			line[b++] = rest_line[c];
		  }
          break;
        case 'd':
          if(IS_SEPARATOR(rest_line[c-1]) && (rest_line[c+1] == 's') && (rest_line[c+2] == 't') && IS_SEPARATOR(rest_line[c+3])) {
            strcpy(&line[b],"ZH:ZL");
            b += 5;
            c += 2;
		  }
          else {
			line[b++] = rest_line[c];
		  } 
          break;
//        case ';':
//          break;
        default:
          line[b++] = rest_line[c];                
	  }
	}
    strcpy(&line[b],"\n"); /* set CR/LF at the end of the line */
		
	
	/*  here we split up the macro arguments into "macro_args"
	 *  Extended macro code interpreter added by TW 2002
	 */
		
	temp = line;
    /* test for advanced parameters */
	if( temp[0] == '[' ) { // there must be "[" " then "]", else it is garbage
      if(!strchr(temp, ']')) {
     	print_msg(pi, MSGTYPE_ERROR, "found no closing ']'");
		return(False);
	  }
  
      // Okay now we are within the advanced code interpreter
  	
	  temp++; // = &temp[1]; // skip the first bracket
	  nmn = malloc(LINEBUFFER_LENGTH);
      if(!nmn) {
	    print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
	    return(False);
	  }
	  strcpy(nmn,macro->name); // create a new macro name buffer
	  c = 1; // byte counter
	  arg = True; // loop flag

	  while(arg) {
		while(IS_HOR_SPACE(temp[0])) { //skip leading spaces
    	  temp++; // = &temp[1];
		}
		off = 0; // pointer offset
		do {
		  switch(temp[off]) { //test current character code
			case ':':
    		  temp[off] = '\0';
			  if(off > 0) {
				c++;
       			macro_args[macro_arg_count++] = temp;
			  }
   			  else {
				print_msg(pi, MSGTYPE_ERROR, "missing register before ':'",nmn);
				return(False);
			  }
   			  break;
			case ']':
 			  arg = False;
    		case ',':
			  a = off;
			  do temp[a--] = '\0'; while( IS_HOR_SPACE(temp[a]) );
      		  if(off > 0) {
       			macro_args[macro_arg_count++] = temp;
				append_type(pi, nmn, c, temp);
				c = 1;
			  }
   			  else {
				append_type(pi, nmn, 0, temp);
				c = 1;
			  } 
			  break;

       		 default:
       		  off++;
		  }
		}
		while(temp[off] != '\0');

		if(arg) temp = &temp[off+1];
	 	else break;
	  }

	  macro = get_macro(pi,nmn);
	  if(macro == NULL) {
	    print_msg(pi, MSGTYPE_ERROR, "Macro %s is not defined !",nmn);
	    return(False);
	  }
      free(nmn);
	}
    /* or else, we handle the macro as normal macro */
    else {
      line = malloc(strlen(rest_line) + 1);
      if(!line) {
        print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
        return(False);
      }
      strcpy(line, rest_line);
      temp = line;
      while(temp) {
        macro_args[macro_arg_count++] = temp;
        temp = get_next_token(temp, TERM_COMMA);
      }
	}
  }

  if(pi->pass == PASS_1) {
	macro_call = calloc(1, sizeof(struct macro_call));
	if(!macro_call) {
	  print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
	  return(False);
	}
	if(pi->last_macro_call)
	  pi->last_macro_call->next = macro_call;
	else
	  pi->first_macro_call = macro_call;
		
	pi->last_macro_call = macro_call;
	macro_call->line_number = pi->fi->line_number;
	macro_call->include_file = pi->fi->include_file;
	macro_call->macro = macro;
	macro_call->prev_on_stack = pi->macro_call;
		
  	if(macro_call->prev_on_stack) {
  	  macro_call->nest_level = macro_call->prev_on_stack->nest_level + 1;
  	  macro_call->prev_line_index = macro_call->prev_on_stack->line_index;
	}
  }
  else {
	for(macro_call = pi->first_macro_call; macro_call; macro_call = macro_call->next) {
	  if((macro_call->include_file->num == pi->fi->include_file->num) && (macro_call->line_number == pi->fi->line_number)) {
		if(pi->macro_call) {
		/* Find correct macro_call when using recursion and nesting */
		  if(macro_call->prev_on_stack == pi->macro_call)
			if((macro_call->nest_level == (pi->macro_call->nest_level + 1)) && (macro_call->prev_line_index == pi->macro_call->line_index))
			  break;
		}
		else break;
	  }
	}
	if(pi->list_line && pi->list_on) {
	  fprintf(pi->list_file, "C:%06x   +  %s\n", pi->cseg_addr, pi->list_line);
	  pi->list_line = NULL;
	}
  }
  
  macro_call->line_index = 0;
  pi->macro_call = macro_call;
  old_macro_line = pi->macro_line;
		
  //printf("\nconvert macro: '%s'\n",macro->name);

  for(pi->macro_line = macro->first_macro_line; pi->macro_line && ok; pi->macro_line = pi->macro_line->next) {
    macro_call->line_index++;
	if(GET_ARG(pi->args, ARG_LISTMAC))
	  pi->list_line = buff;
	else
	  pi->list_line = NULL;
				
	/* here we change jumps/calls within macro that corresponds to macro labels.
   	   Only in case there is an entry in macro_label list */
   
    strcpy(buff,"\0");
    macro_label = get_macro_label(pi->macro_line->line,macro);
	if(macro_label)	{
      /* test if the right macro label has been found */
	  temp = strstr(pi->macro_line->line,macro_label->label);
      c = strlen(macro_label->label);
      if(temp[c] == ':') { /* it is a label definition */
      	macro_label->running_number++;
      	strncpy(buff, macro_label->label, c - 1);
		buff[c - 1] = 0;
        i = strlen(buff) + 2; /* we set the process indeafter label */
        /* add running number to it */
		strcpy(&buff[c-1],itoa(macro_label->running_number, tmp, 10));
		strcat(buff, ":\0");
	  }
      else if(IS_HOR_SPACE(temp[c]) || IS_END_OR_COMMENT(temp[c]))	{ /* it is a jump to a macro defined label */
      	strcpy(buff,pi->macro_line->line);
      	temp = strstr(buff, macro_label->label);
      	i = temp - buff + strlen(macro_label->label);
        strncpy(temp, macro_label->label, c - 1);
      	strcpy(&temp[c-1], itoa(macro_label->running_number, tmp, 10));
	  }
	}
   	else {
      i = 0;
	}

	/* here we check every character of current line */
	for(j = i; pi->macro_line->line[i] != '\0'; i++) {
	  /* check for register place holders */
	  if(pi->macro_line->line[i] == '@') {
  		i++;
  		if(!isdigit(pi->macro_line->line[i]))
		  print_msg(pi, MSGTYPE_ERROR, "@ must be followed by a number");
        else if((pi->macro_line->line[i] - '0') >= macro_arg_count)
          print_msg(pi, MSGTYPE_ERROR, "Missing macro argument (for @%c)", pi->macro_line->line[i]);
        else {
          /* and replace them with given registers */
          strcat(&buff[j], macro_args[pi->macro_line->line[i] - '0']);
          j += strlen(macro_args[pi->macro_line->line[i] - '0']);
		}
	  }
      else if (pi->macro_line->line[i] == ';') {
        strncat(buff, "\n", 1);
        break;
      }
      else {
        strncat(buff, &pi->macro_line->line[i], 1);
	  }
	}
    
    ok = parse_line(pi, buff);
    if(ok) {
	  if((pi->pass == PASS_2) && pi->list_line && pi->list_on)
	    fprintf(pi->list_file, "         %s\n", pi->list_line);
	  if(pi->error_count >= pi->max_errors) {
	    print_msg(pi, MSGTYPE_MESSAGE, "Maximum error count reached. Exiting...");
	    ok = False;
	  break;
	  }
	} 
  }

  pi->macro_line = old_macro_line;
  pi->macro_call = macro_call->prev_on_stack;
  if(rest_line)
    free(line);
  return(ok);
}