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; }
/**************************************************************** * 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); }
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 = ¯o->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 = ¯o_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); }
/* * 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); }
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); }