/* "NETCMP", an simple netlist comparator, Copyright (C) 1985, 1990 California Institute of Technology. Original author: Massimo Sivilotti Unix Port Maintainer: John Lazzaro Maintainers's address: lazzaro@csvax.caltech.edu; CB 425 CU Boulder/Boulder CO 91125. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation (any version). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Output from P2C, the Pascal-to-C translator */ /* From input file "parser.text" */ #include #include #include #include #ifdef linux #include #endif #include "parser.h" #define hash_table_size 65535L /* extern char *strdup(); */ /* hash_table_size = (2*1024) - 1; */ typedef struct node_table_entry { char name[81]; nodetype *node; struct node_table_entry *next; } node_table_entry; typedef node_table_entry *hash_table_type[hash_table_size + 1]; typedef struct param_list { nodetype *node; struct param_list *next; } param_list; typedef struct cell_type { /* Storage of cell definitions. */ char name[81]; long param_count; param_list *parameters; nequivtype *nodes; tequivtype *transistors; struct cell_type *next; } cell_type; static char token[256], fileLine[256], line[256]; static char infilename[81], outfilename[81]; static long line_no; static FILE *infyle; static node_table_entry **hash_table; static node_table_entry *node_table; static char circuit_no; static cell_type *cells; static param_list *paramGarbage; static node_table_entry *nodeTableGarbage; static cell_type *cellGarbage; static long last_orphan_no; static long hash(str_) char *str_; { char str[81]; long l, t; short *sp; long FORLIM; strcpy(str, str_); if (!(strlen(str) & 1)) strcat(str, " "); sp = (short *)str; t = 0; FORLIM = strlen(str) / 2; for (l = 0; l <= FORLIM; l++) { t += *sp; sp++; } return (t % (hash_table_size + 1)); } static param_list *getParamList() { param_list *param; if (paramGarbage != NULL) { param = paramGarbage; paramGarbage = paramGarbage->next; } else param = (param_list *)malloc(sizeof(param_list)); param->node = NULL; param->next = NULL; return param; } static void reclaimParamList(param) param_list **param; { if (*param == NULL) return; /*MAS*/ (*param)->next = paramGarbage; paramGarbage = *param; *param = NULL; } static void print_param_list(params) param_list *params; { param_list *param; printf("Printing parameter list: \n"); printf("List Element -> Node Next \n"); param = params; while (param != NULL) { printf("%12ld ->%12ld%12ld\n", (long)param, (long)param->node, (long)param->next); param = param->next; } } static node_table_entry *getNodeTable() { node_table_entry *nodeTable; if (nodeTableGarbage != NULL) { nodeTable = nodeTableGarbage; nodeTableGarbage = nodeTableGarbage->next; } else nodeTable = (node_table_entry *)malloc(sizeof(node_table_entry)); *nodeTable->name = '\0'; nodeTable->node = NULL; nodeTable->next = NULL; return nodeTable; } static void reclaimNodeTable(nodeTable) node_table_entry **nodeTable; { (*nodeTable)->next = nodeTableGarbage; nodeTableGarbage = *nodeTable; *nodeTable = NULL; } static void reclaimNodeTableList(nodeTable) node_table_entry **nodeTable; { node_table_entry *next; while (*nodeTable != NULL) { next = (*nodeTable)->next; reclaimNodeTable(nodeTable); *nodeTable = next; } } static void reclaimHashTable() { long i; for (i = 0; i <= hash_table_size; i++) reclaimNodeTableList(&hash_table[i]); } static cell_type *getCell() { cell_type *cell; if (cellGarbage != NULL) { cell = cellGarbage; cellGarbage = cellGarbage->next; } else cell = (cell_type *)malloc(sizeof(cell_type)); *cell->name = '\0'; cell->param_count = 0; cell->parameters = NULL; cell->nodes = NULL; cell->transistors = NULL; cell->next = NULL; return cell; } static void reclaimCell(cell) cell_type **cell; { reclaimParamList(&(*cell)->parameters); reclaimNodeList(&(*cell)->nodes->nodes); reclaim_node_class(&(*cell)->nodes); reclaimTranList(&(*cell)->transistors->transistors); reclaim_tran_class(&(*cell)->transistors); (*cell)->next = cellGarbage; cellGarbage = *cell; *cell = NULL; } static void reclaimCellList(cell) cell_type **cell; { cell_type *next; while (*cell != NULL) { next = (*cell)->next; reclaimCell(cell); *cell = next; } } static void init_node_table(nodetabp) node_table_entry **nodetabp; { long i; /* node_table:= NIL; */ for (i = 0; i <= hash_table_size; i++) hash_table[i] = NULL; } static void print_node_table() { node_table_entry *nodetabp; long i; printf("Printing node table: \n"); printf("List Element -> Name Node Next \n"); for (i = 0; i <= hash_table_size; i++) { /* nodetabp:= node_table; */ nodetabp = hash_table[i]; while (nodetabp != NULL) { printf("%12ld -> %s%12ld%12ld\n", (long)nodetabp, nodetabp->name, (long)nodetabp->node, (long)nodetabp->next); nodetabp = nodetabp->next; } } } static nodetype *node_lookup(node_name) char *node_name; { node_table_entry *nodetabp; char match; /* writeln('Line number: ',line_no:0,' ',fileLine); print_node_table; */ match = 0; /* nodetabp:= node_table; */ nodetabp = hash_table[hash(node_name)]; while (nodetabp != NULL && !match) { if (!strcmp(nodetabp->name, node_name)) match = 1; else nodetabp = nodetabp->next; } if (nodetabp == NULL) return NULL; else return (nodetabp->node); } static void insert_in_node_table(nodep, nodename) nodetype *nodep; char *nodename; { node_table_entry *nodetabp; long i; if (node_lookup(nodename) != NULL) { printf("Node name: %s already used.\n", nodename); return; } i = hash(nodename); nodetabp = getNodeTable(); strcpy(nodetabp->name, nodename); /* Copy the node name string. */ nodetabp->node = nodep; /* next:= node_table; */ nodetabp->next = hash_table[i]; /* node_table:= nodetabp; */ hash_table[i] = nodetabp; } static void print_cell_list() { cell_type *celltabp; printf("Printing cell list: \n"); celltabp = cells; while (celltabp != NULL) { printf("%s%12ld\n", celltabp->name, (long)celltabp); celltabp = celltabp->next; } } static cell_type *cell_lookup(cell_name) char *cell_name; { cell_type *cell; char match; match = 0; cell = cells; while (cell != NULL && !match) { if (!strcmp(cell->name, cell_name)) match = 1; else cell = cell->next; } return cell; } char *strltrim(s) register char *s; { while (isspace(*s++)) ; return s - 1; } int strpos2(s, pat, pos) char *s; register char *pat; register int pos; { register char *cp, ch; register int slen; if (--pos < 0) return 0; slen = strlen(s) - pos; cp = s + pos; if (!(ch = *pat++)) return 0; pos = strlen(pat); slen -= pos; while (--slen >= 0) { if (*cp++ == ch && !strncmp(cp, pat, pos)) return cp - s; } return 0; } /* Return the next token from the global variable: line. This temporarily uses */ /* only blanks as separators. Modify line to strip out the found token. The */ /* token is returned by the function and also put into the global variable: token. */ static char *gettoken(Result) char *Result; { long i; char STR1[256]; char *TEMP; strcpy(STR1, strltrim(line)); strcpy(line, STR1); /* MAS - 7/12/88 */ i = strpos2(line, " ", 1); if (i != 0) { /* get token out of 'line' */ sprintf(token, "%.*s", (int)(i - 1), line); strcpy(line, line + i); strcpy(STR1, strltrim(line)); strcpy(line, STR1); return strcpy(Result, token); } if (*line != '\0') { /* rest of line is a single token */ strcpy(token, line); *line = '\0'; return strcpy(Result, token); } else { /* need to get a new line */ fgets(line, 256, infyle); TEMP = strchr(line, '\n'); if (TEMP != NULL) *TEMP = 0; line_no++; gettoken(token); } /* writeln('gettoken returns: ',token); */ return strcpy(Result, token); } /*$if false$ function gettoken: str255; var i : integer; begin i := strpos(line, ' '); if i = 0 then begin token := line; line := ''; end else begin token := str(line, 1, i-1); strdelete(line, 1, i); line := strltrim(line); end; gettoken:= token; end; $end$*/ static long gettokenint() { long i, int_; char STR2[256]; gettoken(STR2); int_ = atol(STR2); i = strlen(STR2) + 1; return int_; } static char *transistor_types_NAMES[] = { "N", "P", "D", "I", "X" } ; /* Add transitor: tran to the transistor list of node: node and increment the */ /* appropriate transitor fanout of the node. */ static void add_gate_tran(tran, node) trantype *tran; nodetype *node; { tran_list_type *tranlist; tranlist = getNodeTran(); tranlist->next = node->trans; /* Link the new transistor list element */ node->trans = tranlist; /* into the nodes transitor list. */ tranlist->tran = tran; switch (tran->t_type) { /* Increment the nodes fanout number. */ case N: node->ng++; break; case P: node->pg++; break; default: printf("Can't handle transistor type: %s\n", transistor_types_NAMES[(long)tran->t_type]); break; } } /* Add transitor: tran to the transistor list of node: node and increment the */ /* appropriate transitor fanout of the node. */ static void add_source_tran(tran, node) trantype *tran; nodetype *node; { tran_list_type *tranlist; tranlist = getNodeTran(); tranlist->next = node->trans; /* Link the new transistor list element */ node->trans = tranlist; /* into the nodes transitor list. */ tranlist->tran = tran; switch (tran->t_type) { /* Increment the nodes fanout number. */ case N: node->ns++; break; case P: node->ps++; break; default: printf("Can't handle transistor type: %s\n", transistor_types_NAMES[(long)tran->t_type]); break; } } static void parseBody (); static void parseCellDefinition() { cell_type *cell; param_list *param; nodetype *node; char STR1[256], STR4[256]; char *TEMP; gettoken(token); if (cell_lookup(gettoken(STR1)) != NULL) { printf("Error: Cell \"%s\" defined second time on line: %s\n", token, fileLine); return; } printf("Parsing cell: %s\n", token); cell = getCell(); strcpy(cell->name, token); cell->nodes = getNEquiv(); /* While we parse the body, we want the */ cell->transistors = getTEquiv(); /* global node and transistor lists to be */ nequiv = cell->nodes; /* those of this cell. I hope somebody */ tequiv = cell->transistors; /* saved the real global lists. */ while (strcmp(gettoken(STR4), ";")) { param = getParamList(); param->node = getNode(); node = param->node; node->names = getName(); #if 1 node->names->name = strdup(token); #else strcpy(node->names->name, token); #endif insert_in_node_table(node, token); node->next = nequiv->nodes; /* Link this node into global (hah hah)*/ nequiv->nodes = node; /* equivalence class. */ node->my_equiv_class = nequiv; nequiv->count++; /* Increment my equivalence classes */ /* node count. */ node->my_circuit = circuit_no; param->next = cell->parameters; /* Link a parameter into the cell's list. */ cell->parameters = param; cell->param_count++; } cell->next = cells; /* Link this cell into the global cell */ cells = cell; /* list. */ fgets(line, 256, infyle); TEMP = strchr(line, '\n'); if (TEMP != NULL) *TEMP = 0; line_no++; parseBody(); reclaimHashTable(); } static void reportError(str) char *str; { printf("\nLine %12ld: %s\n", line_no, fileLine); printf("Error: %s\n", str); } static void parseNode() { nodetype *node; nametype *last_name; char STR1[256]; node = getNode(); node->strength = gettokenint(); node->names = getName(); #if 1 gettoken(STR1); node->names->name = strdup(STR1); #else gettoken(node->names->name); /* Put first node name first on the list. */ #endif last_name = node->names; if (!strcmp(token, ";")) reportError("No node name given for node."); else insert_in_node_table(node, token); while (strcmp(gettoken(STR1), ";")) { /* Put successive names next */ last_name->next = getName(); /* on the list. */ last_name = last_name->next; #if 1 last_name->name = strdup(token); #else strcpy(last_name->name, token); #endif insert_in_node_table(node, token); } node->next = nequiv->nodes; /* Link this node into global */ nequiv->nodes = node; /* equivalence class. */ node->my_equiv_class = nequiv; nequiv->count++; /* Increment my equivalence classes */ /* node count. */ node->my_circuit = circuit_no; } static void parseEquate() { printf("Can't handle equates. Line: %s\n", fileLine); } static void parseForget() { printf("Can't handle forgets. Line: %s\n", fileLine); } static void isNodeDefined(node) nodetype *node; { if (node != NULL) return; printf("Error: Node \"%s\" not defined. Used on line: %s\n", token, fileLine); if (dbug) print_node_table(); } static void parseTransistor(tran) trantype *tran; { char STR1[256]; tran->strength = gettokenint(); tran->gate = node_lookup(gettoken(STR1)); /* Point this transistor to its */ isNodeDefined(tran->gate); /* three nodes. */ tran->s1 = node_lookup(gettoken(STR1)); isNodeDefined(tran->s1); tran->s2 = node_lookup(gettoken(STR1)); isNodeDefined(tran->s2); add_gate_tran(tran, tran->gate); /* Add this transitor to the transistor */ add_source_tran(tran, tran->s1); /* lists of its three nodes. */ add_source_tran(tran, tran->s2); tran->next = tequiv->transistors; /* Link this transistor into global */ tequiv->transistors = tran; /* equivalence class. */ tran->my_equiv_class = tequiv; tequiv->count++; /* Increment my equivalence classes */ /* transistor count. */ tran->my_circuit = circuit_no; } static void parseNTran() { trantype *tran; tran = getTran(); tran->t_type = N; parseTransistor(tran); } static void parsePTran() { trantype *tran; tran = getTran(); tran->t_type = P; parseTransistor(tran); } static void parseDTran() { printf("Can't handle D transistors. Line: %s\n", fileLine); } static void parseBlock() { printf("Can't handle blocks. Line: %s\n", fileLine); } /* Append the node names of 'node' with 'prefix' to the node name list of */ /* 'node_copy'. Actually do an append, not a prepend to leave the first name */ /* (the "best" name) in the first position. */ static void appendNames(node_copy, node, prefix) nodetype *node_copy, *node; char *prefix; { nametype *name, *copy_name; copy_name = node_copy->names; if (copy_name == NULL) { /* If no name then prepend */ name = node->names; /* the list. */ while (name != NULL) { char tmpstr[200]; copy_name = getName(); copy_name->next = node_copy->names; node_copy->names = copy_name; #if 1 sprintf(tmpstr, "%s%s", prefix, name->name); copy_name->name = strdup(tmpstr); #else sprintf(copy_name->name, "%s%s", prefix, name->name); #endif name = name->next; } return; } while (copy_name->next != NULL) copy_name = copy_name->next; name = node->names; while (name != NULL) { char tmpstr[200]; copy_name->next = getName(); copy_name = copy_name->next; #if 1 sprintf(tmpstr, "%s%s", prefix, name->name); copy_name->name = strdup(tmpstr); #else sprintf(copy_name->name, "%s%s", prefix, name->name); #endif name = name->next; } /* Else append to the end. */ } static void parseInstance() { char instanceName[81]; cell_type *cell; param_list *cell_param, *param, *params; long param_count; nodetype *node, *node_copy; trantype *tran; tran_list_type *tran_list, *tran_list_copy; char STR1[256]; char STR2[164]; param_count = 0; cell = cell_lookup(gettoken(STR1)); /* Cell name. */ if (cell == NULL) printf("Error: Cell \"%s\" not defined. Used on line: %s\n", token, fileLine); gettoken(instanceName); /* Instance name. */ params = NULL; /* Make the calling nodes into a parameter list. */ while (strcmp(gettoken(STR1), ";")) { /* Parameters. */ param = getParamList(); param->next = params; /* Link this parameter */ params = param; /* into the list. */ param->node = node_lookup(token); /*writeln('x ',ord(param),' ->',ord(param^.node),ord(param^.next));*/ if (param->node == NULL) printf("Error: Undefined Node: %s used on line: %s\n", token, fileLine); param_count++; } if (param_count != cell->param_count) printf("Error: Cell defined with %ld parameters instanced with %ld on line: %s\n", cell->param_count, param_count, line); /* Make each of the cells parameters link to the calling nodes. At the */ /* same time update the calling nodes fanout counts. */ /* writeln('Calling parameter list.'); print_param_list(params); writeln('Defining parameter list.'); print_param_list(cell^.parameters); */ param = params; cell_param = cell->parameters; while (param != NULL && cell_param != NULL) { cell_param->node->clone = param->node; param->node->pg += cell_param->node->pg; param->node->ng += cell_param->node->ng; param->node->ps += cell_param->node->ps; param->node->ns += cell_param->node->ns; param = param->next; cell_param = cell_param->next; } /* Make a new transistor list without any contents yet. */ tran = cell->transistors->transistors; while (tran != NULL) { tran->clone = getTran(); tran = tran->next; } /* Copy the internal nodes of the cell. They are the ones without the */ /* clone (parameter) links established above yet. */ node = cell->nodes->nodes; while (node != NULL) { /* If node is an internal one then make a copy ..... */ if (node->clone == NULL) { node_copy = getNode(); node->clone = node_copy; node_copy->strength = node->strength; sprintf(STR2, "%s.%s/", cell->name, instanceName); appendNames(node_copy, node, STR2); /**/ node_copy->next = nequiv->nodes; /* Link this node into global */ nequiv->nodes = node_copy; /* equivalence class. */ node_copy->my_equiv_class = nequiv; nequiv->count++; /* Increment my equivalence classes */ /* node count. */ node_copy->pg = node->pg; node_copy->ng = node->ng; node_copy->ps = node->ps; node_copy->ns = node->ns; node_copy->my_circuit = node->my_circuit; } else { /* ..... otherwise just use the existing one. */ node_copy = node->clone; sprintf(STR2, "%s.%s/", cell->name, instanceName); appendNames(node_copy, node, STR2); } /* Clone this node's transistor list (in reverse order - its easier) */ /* pointing to the cloned transistors. */ tran_list = node->trans; while (tran_list != NULL) { tran_list_copy = getNodeTran(); tran_list_copy->next = node_copy->trans; node_copy->trans = tran_list_copy; tran_list_copy->tran = tran_list->tran->clone; tran_list = tran_list->next; } node = node->next; } /* print_node_equiv_class(cell^.nodes); */ /* Copy the transistors while following the indirection links if they are */ /* connected to any parameter nodes. At the same time add the clones */ /* into the global transistor list. */ tran = cell->transistors->transistors; while (tran != NULL) { tran->clone->strength = tran->strength; tran->clone->gate = tran->gate->clone; tran->clone->s1 = tran->s1->clone; tran->clone->s2 = tran->s2->clone; tran->clone->t_type = tran->t_type; tran->clone->next = tequiv->transistors; /* Link this transistor into global */ tequiv->transistors = tran->clone; /* equivalence class. */ tran->clone->my_equiv_class = tequiv; tequiv->count++; /* Increment my equivalence classes */ /* transistor count. */ tran->clone->my_circuit = tran->my_circuit; tran = tran->next; } /* Run through all the cell (definition) nodes clearing the indirection. */ node = cell->nodes->nodes; while (node != NULL) { node->clone = NULL; node = node->next; } /* Think about reclaiming the parameter list. */ /* print_tran_equiv_class(tequiv); */ } static void parseVector() { printf("Can't handle vectors. Line: %s\n", fileLine); } static void parseInclude() { printf("Can't handle includes. Line: %s\n", fileLine); } static void parseBody() { char done; char STR1[256]; char *TEMP; done = 0; while (!feof(infyle) && !done) { strcpy(fileLine, line); switch (gettoken(STR1)[0]) { case '|': /* Ignore comment lines. */ break; case 'c': case 'C': printf("Attempt to define a cell with a cell definition on line: %s\n", fileLine); break; case 'i': case 'I': parseNode(); break; case 's': case 'S': parseNode(); break; case 'e': case 'E': parseEquate(); break; case 'f': case 'F': parseForget(); break; case 'n': case 'N': parseNTran(); break; case 'p': case 'P': parsePTran(); break; case 'd': case 'D': parseDTran(); break; case 'b': case 'B': parseBlock(); break; case 'h': case 'H': parseInstance(); break; case 'v': case 'V': parseVector(); break; case 'm': case 'M': parseInclude(); break; case '.': done = 1; break; default: printf("Unknown entry in line: %s\n", fileLine); break; } if (done) break; fgets(line, 256, infyle); TEMP = strchr(line, '\n'); if (TEMP != NULL) *TEMP = 0; line_no++; } if (dbug) print_node_table(); } static void remove_orphans(orphan_no) long *orphan_no; { nodetype *node, *last, *next; *orphan_no = 0; last = NULL; node = nequiv->nodes; while (node != NULL) { if (node->trans != NULL) { last = node; node = node->next; continue; } if (node->ng != 0 || node->pg != 0 || node->ns != 0 || node->ps != 0) printf("Error: Inconsistent data structure.\n"); (*orphan_no)++; next = node->next; if (last == NULL) nequiv->nodes = next; /* Remove node from list. */ else last->next = next; reclaimNode(&node); node = next; } } /* Parse the whole NTK file. */ void parsefile(circ_no, infilename) char circ_no; char *infilename; { char done; trantype *tran; nodetype *node; long ntran_no, ptran_no, node_no; /* number of p, n, and nodes */ long orphan_no; nequivtype *save_nequiv; tequivtype *save_tequiv; char *TEMP; paramGarbage = NULL; cellGarbage = NULL; nodeTableGarbage = NULL; cells = NULL; hash_table = (node_table_entry **)malloc(sizeof(hash_table_type)); init_node_table(&node_table); save_nequiv = nequiv; save_tequiv = tequiv; circuit_no = circ_no; line_no = 0; if (infyle != NULL) infyle = freopen(infilename, "r", infyle); else infyle = fopen(infilename, "r"); if (infyle == NULL) perror("FileNotFound"); printf("Parsing file: %s\n", infilename); fprintf(outfyle, "Parsing file: %s\n", infilename); done = 0; while (!feof(infyle) && !done) { fgets(line, 256, infyle); TEMP = strchr(line, '\n'); if (TEMP != NULL) *TEMP = 0; line_no++; strcpy(fileLine, line); /* writeln('Line: >>',fileLine,'<<'); */ switch (line[0]) { case '|': /* Ignore comment lines. */ break; case 'c': case 'C': parseCellDefinition(); break; default: done = 1; break; } } nequiv = save_nequiv; tequiv = save_tequiv; parseBody(); if (infyle != NULL) fclose(infyle); infyle = NULL; reclaimCellList(&cells); /* Count the transistors. */ ntran_no = 0; ptran_no = 0; tran = tequiv->transistors; while (tran != NULL) { if (tran->t_type == N && tran->my_circuit == circ_no) ntran_no++; if (tran->t_type == P && tran->my_circuit == circ_no) ptran_no++; tran = tran->next; } remove_orphans(&orphan_no); /* Count the nodes. */ node_no = 0; node = nequiv->nodes; while (node != NULL) { if (node->my_circuit == circ_no) node_no++; node = node->next; } printf("Found: %ld N Transistors, %ld P Transistors, %ld Total Transistors,\n", ntran_no, ptran_no, ntran_no + ptran_no); printf(" %ld Non-orphan Nodes, %ld Orphans, %ld Total Nodes.\n", node_no, orphan_no, node_no + orphan_no); fprintf(outfyle, "Found: %ld N Transistors, %ld P Transistors, %ld Total Transistors,\n", ntran_no, ptran_no, ntran_no + ptran_no); fprintf(outfyle, " %ld Non-orphan Nodes, %ld Orphans, %ld Total Nodes.\n\n", node_no, orphan_no, node_no + orphan_no); if (circuit_no == 2 && last_orphan_no != orphan_no) { printf("**** Warning: Mismatch in number of orphan nodes. ****\n"); fprintf(outfyle, "**** Warning: Mismatch in number of orphan nodes. ****\n\n"); } last_orphan_no = orphan_no; /* if true then begin */ if (dbug) { print_node_equiv_class(nequiv); print_tran_equiv_class(tequiv); } free(hash_table); } #ifdef ultrix char *strdup(s) char *s; { char *s1; if (s == (char *) NULL) return (char *) NULL; if ((s1 = (char *) malloc(strlen(s) + 1)) == (char *) NULL) { perror("out of memory"); exit(1); } strcpy(s1, s); return s1; } #endif /* End. */