//#include <iostream>
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/document.h"
#include <cstdio>
using namespace rapidjson;
//using namespace std;
#define MAXSIZE 16*1024
#define MAXPORT 1024
int CCOUNT = 0;
char cellsPrefix[1024][32];
/*
"INV",
"NAND",
"NOR",
"XNOR",
"AND",
"OR",
"XOR",
"AOI",
"MUX",
"CLKBUF",
"FAX",
"HAX",
"DFFSR",
"DFFPOS",
"DFFNEG"
};
*/
typedef struct {char type[32]; char name[32];char pins[32][32]; char nets[32][32]; unsigned pCnt;} GATE;
typedef struct {unsigned dir;char name[32];unsigned isBus;unsigned busSize;} PORT;
typedef enum {OUT=0, IN=1, CELL, FFD, FFQ} NODE_T;
typedef struct node_struct {NODE_T type; int fo_instances[32]; int fo_cnt; int instance;} NODE;
NODE graphNodes[MAXSIZE];
GATE circuitGates[MAXSIZE];
PORT circuitPorts[MAXPORT];
unsigned int gCount = 0, nCount = 0, ffCount = 0, portCount=0;
unsigned int nodeCount = 0;
Document doc;
/* Graph */
int buildGraph()
{
int i;
for(i=0;i<portCount;i++){
graphNodes[nodeCount].type = (NODE_T) circuitPorts[i].dir;
graphNodes[nodeCount].instance = i;
nodeCount++;
}
for(i=0;i<gCount;i++){
//graphNodes[nodeCount].type = (NODE_T) circuitPorts[i].dir;
graphNodes[nodeCount].instance = i;
}
}
/*
int findFO(int gate, char *net, int list[]){
int i, e;
// fnd all cnnected cells to that net
for(i=0; i<gCount; i++){
if(i!=g){
for(e=0; e<circuitGates[i].pCnt; e++){
//if()
}
}
}
}
*/
//
int isCell(char *str)
{
int i;
for(i=0; i<CCOUNT; i++){
if(strstr(str, cellsPrefix[i]))
return 1;
}
return 0;
}
int getCell(FILE *fp, char *s)
{
char buff[512];
while(1) {
if(!fgets(buff, 511, fp)) return 0;
strtok(buff, "\n");
strcat(s, buff);
if(strchr(buff,';')) break;
}
return 1;
}
int getPinNet(char *s, char *n)
{
char *p=strchr(s,'(');
if(!*p) return 0;
p++;
while(*p!=')') *n++=*p++;
*n='\0';
}
int getPinName(char *s, char *p)
{
s++;
while(*s!='(') *p++=*s++;
*p='\0';
}
int getCellPins(char *s)
{
char *p=s;
char net[32], pin[32];
while(p=strchr(p,'.')){
getPinName(p, pin);
getPinNet(p, net);
strcpy(circuitGates[gCount].pins[circuitGates[gCount].pCnt],pin);
strcpy(circuitGates[gCount].nets[circuitGates[gCount].pCnt++],net);
//printf("pin: %s\n", net);
p++;
}
}
#define ISW(s) (*s==' ' || *s=='\t')
int parseNameAndType(char *s, char *nm, char *type)
{
while(ISW(s)) s++;
while(!ISW(s)) *type++=*s++;
*type = '\0';
while(ISW(s)) s++;
while(!ISW(s)) *nm++=*s++;
*nm = '\0';
}
/*
int parseToken (char *s, char *tok, char *sep)
{
while(ISW(*s)) s++;
while
}*/
int parseRange(char *s, unsigned *r1, unsigned *r2){
char num[32];
char *p = num;
s = strchr(s, '[');
s++;
while(*s!=':') *p++=*s++;
*p = '\0';
*r1=atoi(num);
p = num;
//s = strchr(s, ':');
while(*s!=']') *p++=*s++;
*p = '\0';
*r2=atoi(num);
}
int parseGLV(FILE *fp)
{
char line[512], tmp[512];
char pin[32];
char gname[32], gtype[32], pname[32];
unsigned r1, r2, e, s;
char *p, *l;
while(fgets(line,511,fp)){
if(isCell(line)) {
strtok(line, "\n");
if(getCell(fp, tmp))
strcat(line, tmp);
//printf("tmp: %s\n", tmp);
//printf("found gate %s\n", line);
parseNameAndType(line, gname, gtype);
strcpy(circuitGates[gCount].type, gtype);
strcpy(circuitGates[gCount].name, gname);
getCellPins(line);
gCount++;
if(strstr(line,"DFF")) ffCount++;
line[0]='\0';
tmp[0]='\0';
} else if(strstr(line, "wire")){
// ignore internal wires inherited from the RTL
if(!strstr(line, "]"))
nCount++;
} else if(strstr(line, "input")!=NULL || strstr(line, "output")!=NULL){
if(strchr(line,'[')) {
parseRange(line, &r1, &r2);
if(r1>r2) {
s = r2;
e = r1;
} else {
s = r1;
e = r2;
}
l = strchr(line, ']');
l++;
p=tmp;
while(ISW(l)) l++;
while(*l != ';') *p++=*l++;
*p='\0';
for(int i=s; i<=e; i++){
sprintf(circuitPorts[portCount].name, "%s[%d]",tmp,i);
if( strstr(line, "output"))
circuitPorts[portCount].dir = 0;
else
circuitPorts[portCount].dir = 1;
circuitPorts[portCount].isBus = 1;
portCount++;
}
}
else {
circuitPorts[portCount].isBus = 0;
l = strstr(line, "put");
//if(l==NULL)
//l=line;
l+=3;
p=tmp;
while(ISW(l)) l++;
while(*l != ';') *p++=*l++;
*p='\0';
strcpy(circuitPorts[portCount].name, tmp);
//circuitPorts[portCount].dir = 1;
if( strstr(line, "output"))
circuitPorts[portCount].dir = 0;
else
circuitPorts[portCount].dir = 1;
portCount++;
}
}
}
}
/* LIST */
typedef struct {int count; char items[256][32];} SLIST;
SLIST * lstNew(){
SLIST *l = (SLIST *) malloc (sizeof(SLIST));
l->count = 0;
return l;
}
int lstAdd(SLIST *lst, char item[32]){
strcpy(lst->items[lst->count], item);
lst->count++;
return (lst->count)-1;
}
int lstFind(SLIST *lst, char item[32]){
int i;
for(i=0; i<(lst->count); i++)
if(!strcmp(lst->items[i],item)) return i;
return -1;
}
int lstFindAdd(SLIST *lst, char item[32]){
int x = lstFind(lst, item);
if((x>-1))
return x;
else
return lstAdd(lst,item);
}
/* */
#define SCL_COUNT 256
int dumpGates()
{
int i, e, f;
int stats[SCL_COUNT], areas[SCL_COUNT];
int area = 0;
SLIST *cells;
cells = lstNew();
for(e=0; e<SCL_COUNT; e++) {stats[e]=0;areas[e]=0;}
for(i=0; i<gCount; i++) {
//printf("%d: %s\n", i, circuitGates[i].type);
if(strstr( circuitGates[i].type,"_DLATCH_P_")){
printf("Design Exception: The design infers a latch! Instatnce name: %s\n", circuitGates[i].name);
exit(-100);
}
f = lstFindAdd(cells, circuitGates[i].type);
stats[f]++;
areas[f] += doc["cells"][circuitGates[i].type]["area"].GetInt();
area = area + doc["cells"][circuitGates[i].type]["area"].GetInt();
}
/*
for(i=0; i<gCount; i++){
//printf("JSON : %d\n", doc["cells"][circuitGates[i].type]["area"].GetInt());
area = area + doc["cells"][circuitGates[i].type]["area"].GetInt();
for(e=0; e<CCOUNT; e++)
if(strstr(circuitGates[i].type,cellsPrefix[e])) {
stats[e]++;
break;
}
}
*/
for(e=0; e<cells->count; e++) {
printf("%s\tCount:%d, Area: %d\n", cells->items[e], stats[e], areas[e]);
}
printf("Total Cell Area: %d \n", area);
printf("Equivalent NAND2x1 Gates count: %d\n",area/doc["cells"]["NAND2X1"]["area"].GetInt());
}
/*
int getFO(int g, int fo[]){
int foc = 0;
int i;
for(i=0; i<gCount; i++) {
if(!strcmp(circuitGates[g].pins[]))
}
}
*/
int loadSCL(char *fn)
{
int size;
char tmp[32];
FILE* fp = fopen(fn, "r"); // non-Windows use "r"
fseek(fp, 0, SEEK_END); // seek to end of file
size = ftell(fp); // get current file pointer
fseek(fp, 0, SEEK_SET); // seek back to beginning of file
char *readBuffer = (char *) malloc(size);
FileReadStream is(fp, readBuffer, size);
doc.ParseStream(is);
//printf("\nJSON : %d\n", doc["cells"]["AND2X1"]["area"].GetInt());
for (Value::ConstMemberIterator itr = doc["cells"].MemberBegin();
itr != doc["cells"].MemberEnd(); ++itr)
{
strcpy(tmp, itr->name.GetString());
if(!strcmp(tmp,"input")) continue;
if(!strcmp(tmp,"output")) continue;
if(!strcmp(tmp,"gnd")) continue;
if(!strcmp(tmp,"vdd")) continue;
strcpy(cellsPrefix[CCOUNT],tmp);
CCOUNT++;
printf("Type of member %s %s\n", itr->name.GetString(),cellsPrefix[CCOUNT-1]);
}
fclose(fp);
}
int main(int argc, char *argv[]) {
FILE *fp;
loadSCL("osu350.json");
if((fp=fopen(argv[1],"r"))!=NULL){
parseGLV(fp);
}
dumpGates();
printf("total number of cells: %d (%d Flip FLops)\nTotal number of nets: %d\nTotal number of ports: %d\n", gCount, ffCount, nCount, portCount);
fclose(fp);
//loadSCL("osu350.json");
return 0;
}
Sharing settings
Ly8jaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlICJzdGRpby5oIgojaW5jbHVkZSAic3RyaW5nLmgiCiNpbmNsdWRlICJzdGRsaWIuaCIKCiNpbmNsdWRlICJyYXBpZGpzb24vZmlsZXJlYWRzdHJlYW0uaCIKI2luY2x1ZGUgInJhcGlkanNvbi9kb2N1bWVudC5oIgojaW5jbHVkZSA8Y3N0ZGlvPgoKdXNpbmcgbmFtZXNwYWNlIHJhcGlkanNvbjsKCgovL3VzaW5nIG5hbWVzcGFjZSBzdGQ7CgojZGVmaW5lICAgICBNQVhTSVpFICAgICAxNioxMDI0CiNkZWZpbmUgICAgIE1BWFBPUlQgICAgIDEwMjQKCmludCBDQ09VTlQgPSAwOwoKY2hhciBjZWxsc1ByZWZpeFsxMDI0XVszMl07Ci8qCiAiSU5WIiwKICJOQU5EIiwKICJOT1IiLAogIlhOT1IiLAogIkFORCIsCiAiT1IiLAogIlhPUiIsCiAiQU9JIiwKICJNVVgiLAogIkNMS0JVRiIsCiAiRkFYIiwKICJIQVgiLAogIkRGRlNSIiwKICJERkZQT1MiLAogIkRGRk5FRyIKIH07CiAqLwoKdHlwZWRlZiBzdHJ1Y3Qge2NoYXIgdHlwZVszMl07IGNoYXIgbmFtZVszMl07Y2hhciBwaW5zWzMyXVszMl07IGNoYXIgbmV0c1szMl1bMzJdOyB1bnNpZ25lZCBwQ250O30gR0FURTsKdHlwZWRlZiBzdHJ1Y3Qge3Vuc2lnbmVkIGRpcjtjaGFyIG5hbWVbMzJdO3Vuc2lnbmVkIGlzQnVzO3Vuc2lnbmVkIGJ1c1NpemU7fSBQT1JUOwoKdHlwZWRlZiBlbnVtIHtPVVQ9MCwgSU49MSwgQ0VMTCwgRkZELCBGRlF9IE5PREVfVDsKdHlwZWRlZiBzdHJ1Y3Qgbm9kZV9zdHJ1Y3Qge05PREVfVCB0eXBlOyBpbnQgZm9faW5zdGFuY2VzWzMyXTsgaW50IGZvX2NudDsgaW50IGluc3RhbmNlO30gTk9ERTsKTk9ERSBncmFwaE5vZGVzW01BWFNJWkVdOwoKR0FURSBjaXJjdWl0R2F0ZXNbTUFYU0laRV07ClBPUlQgY2lyY3VpdFBvcnRzW01BWFBPUlRdOwoKdW5zaWduZWQgaW50IGdDb3VudCA9IDAsIG5Db3VudCA9IDAsIGZmQ291bnQgPSAwLCBwb3J0Q291bnQ9MDsKdW5zaWduZWQgaW50IG5vZGVDb3VudCA9IDA7CgoKRG9jdW1lbnQgZG9jOwoKCi8qIEdyYXBoICovCmludCBidWlsZEdyYXBoKCkKewogICAgaW50IGk7CiAgICBmb3IoaT0wO2k8cG9ydENvdW50O2krKyl7CiAgICAgICAgZ3JhcGhOb2Rlc1tub2RlQ291bnRdLnR5cGUgPSAoTk9ERV9UKSBjaXJjdWl0UG9ydHNbaV0uZGlyOwogICAgICAgIGdyYXBoTm9kZXNbbm9kZUNvdW50XS5pbnN0YW5jZSA9IGk7CiAgICAgICAgbm9kZUNvdW50Kys7CiAgICB9CiAgICBmb3IoaT0wO2k8Z0NvdW50O2krKyl7CiAgICAgICAgLy9ncmFwaE5vZGVzW25vZGVDb3VudF0udHlwZSA9IChOT0RFX1QpIGNpcmN1aXRQb3J0c1tpXS5kaXI7CiAgICAgICAgZ3JhcGhOb2Rlc1tub2RlQ291bnRdLmluc3RhbmNlID0gaTsKICAgIH0KICAgIAogICAgCn0KLyoKIGludCBmaW5kRk8oaW50IGdhdGUsIGNoYXIgKm5ldCwgaW50IGxpc3RbXSl7CiBpbnQgaSwgZTsKIC8vIGZuZCBhbGwgY25uZWN0ZWQgY2VsbHMgdG8gdGhhdCBuZXQKIGZvcihpPTA7IGk8Z0NvdW50OyBpKyspewogaWYoaSE9Zyl7CiBmb3IoZT0wOyBlPGNpcmN1aXRHYXRlc1tpXS5wQ250OyBlKyspewogLy9pZigpCiB9CiB9CiB9CiB9CiAKICovCi8vCgppbnQgaXNDZWxsKGNoYXIgKnN0cikKewogICAgaW50IGk7CiAgICBmb3IoaT0wOyBpPENDT1VOVDsgaSsrKXsKICAgICAgICBpZihzdHJzdHIoc3RyLCBjZWxsc1ByZWZpeFtpXSkpCiAgICAgICAgICAgIHJldHVybiAxOwogICAgfQogICAgcmV0dXJuIDA7Cn0KCmludCBnZXRDZWxsKEZJTEUgKmZwLCBjaGFyICpzKQp7CiAgICBjaGFyIGJ1ZmZbNTEyXTsKICAgIHdoaWxlKDEpIHsKICAgICAgICBpZighZmdldHMoYnVmZiwgNTExLCBmcCkpIHJldHVybiAwOwogICAgICAgIHN0cnRvayhidWZmLCAiXG4iKTsKICAgICAgICBzdHJjYXQocywgYnVmZik7CiAgICAgICAgaWYoc3RyY2hyKGJ1ZmYsJzsnKSkgYnJlYWs7CiAgICB9CiAgICByZXR1cm4gMTsKfQoKaW50IGdldFBpbk5ldChjaGFyICpzLCBjaGFyICpuKQp7CiAgICBjaGFyICpwPXN0cmNocihzLCcoJyk7CiAgICBpZighKnApIHJldHVybiAwOwogICAgcCsrOwogICAgd2hpbGUoKnAhPScpJykgKm4rKz0qcCsrOwogICAgKm49J1wwJzsKfQoKaW50IGdldFBpbk5hbWUoY2hhciAqcywgY2hhciAqcCkKewogICAgcysrOwogICAgd2hpbGUoKnMhPScoJykgKnArKz0qcysrOwogICAgKnA9J1wwJzsKfQoKaW50IGdldENlbGxQaW5zKGNoYXIgKnMpCnsKICAgIGNoYXIgKnA9czsKICAgIGNoYXIgbmV0WzMyXSwgcGluWzMyXTsKICAgIHdoaWxlKHA9c3RyY2hyKHAsJy4nKSl7CiAgICAgICAgZ2V0UGluTmFtZShwLCBwaW4pOwogICAgICAgIGdldFBpbk5ldChwLCBuZXQpOwogICAgICAgIHN0cmNweShjaXJjdWl0R2F0ZXNbZ0NvdW50XS5waW5zW2NpcmN1aXRHYXRlc1tnQ291bnRdLnBDbnRdLHBpbik7CiAgICAgICAgc3RyY3B5KGNpcmN1aXRHYXRlc1tnQ291bnRdLm5ldHNbY2lyY3VpdEdhdGVzW2dDb3VudF0ucENudCsrXSxuZXQpOwogICAgICAgIC8vcHJpbnRmKCJwaW46ICVzXG4iLCBuZXQpOwogICAgICAgIHArKzsKICAgIH0KfQoKI2RlZmluZSAgICAgSVNXKHMpICAgICAoKnM9PScgJyB8fCAqcz09J1x0JykKaW50IHBhcnNlTmFtZUFuZFR5cGUoY2hhciAqcywgY2hhciAqbm0sIGNoYXIgKnR5cGUpCnsKICAgIHdoaWxlKElTVyhzKSkgcysrOwogICAgd2hpbGUoIUlTVyhzKSkgKnR5cGUrKz0qcysrOwogICAgKnR5cGUgPSAnXDAnOwogICAgd2hpbGUoSVNXKHMpKSBzKys7CiAgICB3aGlsZSghSVNXKHMpKSAqbm0rKz0qcysrOwogICAgKm5tID0gJ1wwJzsKfQovKgogaW50IHBhcnNlVG9rZW4gKGNoYXIgKnMsIGNoYXIgKnRvaywgY2hhciAqc2VwKQogewogd2hpbGUoSVNXKCpzKSkgcysrOwogd2hpbGUKIH0qLwppbnQgcGFyc2VSYW5nZShjaGFyICpzLCB1bnNpZ25lZCAqcjEsIHVuc2lnbmVkICpyMil7CiAgICBjaGFyIG51bVszMl07CiAgICBjaGFyICpwID0gbnVtOwogICAgcyA9IHN0cmNocihzLCAnWycpOwogICAgcysrOwogICAgd2hpbGUoKnMhPSc6JykgKnArKz0qcysrOwogICAgKnAgPSAnXDAnOwogICAgKnIxPWF0b2kobnVtKTsKICAgIHAgPSBudW07CiAgICAvL3MgPSBzdHJjaHIocywgJzonKTsKICAgIHdoaWxlKCpzIT0nXScpICpwKys9KnMrKzsKICAgICpwID0gJ1wwJzsKICAgICpyMj1hdG9pKG51bSk7Cn0KCgppbnQgcGFyc2VHTFYoRklMRSAqZnApCnsKICAgIGNoYXIgbGluZVs1MTJdLCB0bXBbNTEyXTsKICAgIGNoYXIgcGluWzMyXTsKICAgIGNoYXIgZ25hbWVbMzJdLCBndHlwZVszMl0sIHBuYW1lWzMyXTsKICAgIHVuc2lnbmVkIHIxLCByMiwgZSwgczsKICAgIGNoYXIgKnAsICpsOwogICAgCiAgICB3aGlsZShmZ2V0cyhsaW5lLDUxMSxmcCkpewogICAgICAgIGlmKGlzQ2VsbChsaW5lKSkgewogICAgICAgICAgICBzdHJ0b2sobGluZSwgIlxuIik7CiAgICAgICAgICAgIGlmKGdldENlbGwoZnAsIHRtcCkpCiAgICAgICAgICAgICAgICBzdHJjYXQobGluZSwgdG1wKTsKICAgICAgICAgICAgLy9wcmludGYoInRtcDogJXNcbiIsIHRtcCk7CiAgICAgICAgICAgIC8vcHJpbnRmKCJmb3VuZCBnYXRlICVzXG4iLCBsaW5lKTsKICAgICAgICAgICAgcGFyc2VOYW1lQW5kVHlwZShsaW5lLCBnbmFtZSwgZ3R5cGUpOwogICAgICAgICAgICBzdHJjcHkoY2lyY3VpdEdhdGVzW2dDb3VudF0udHlwZSwgZ3R5cGUpOwogICAgICAgICAgICBzdHJjcHkoY2lyY3VpdEdhdGVzW2dDb3VudF0ubmFtZSwgZ25hbWUpOwogICAgICAgICAgICBnZXRDZWxsUGlucyhsaW5lKTsKICAgICAgICAgICAgZ0NvdW50Kys7CiAgICAgICAgICAgIGlmKHN0cnN0cihsaW5lLCJERkYiKSkgZmZDb3VudCsrOwogICAgICAgICAgICBsaW5lWzBdPSdcMCc7CiAgICAgICAgICAgIHRtcFswXT0nXDAnOwogICAgICAgIH0gZWxzZSBpZihzdHJzdHIobGluZSwgIndpcmUiKSl7CiAgICAgICAgICAgIC8vIGlnbm9yZSBpbnRlcm5hbCB3aXJlcyBpbmhlcml0ZWQgZnJvbSB0aGUgUlRMCiAgICAgICAgICAgIGlmKCFzdHJzdHIobGluZSwgIl0iKSkKICAgICAgICAgICAgICAgIG5Db3VudCsrOwogICAgICAgIH0gZWxzZSBpZihzdHJzdHIobGluZSwgImlucHV0IikhPU5VTEwgfHwgc3Ryc3RyKGxpbmUsICJvdXRwdXQiKSE9TlVMTCl7CiAgICAgICAgICAgIGlmKHN0cmNocihsaW5lLCdbJykpIHsKICAgICAgICAgICAgICAgIHBhcnNlUmFuZ2UobGluZSwgJnIxLCAmcjIpOwogICAgICAgICAgICAgICAgaWYocjE+cjIpIHsKICAgICAgICAgICAgICAgICAgICBzID0gcjI7CiAgICAgICAgICAgICAgICAgICAgZSA9IHIxOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBzID0gcjE7CiAgICAgICAgICAgICAgICAgICAgZSA9IHIyOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgbCA9IHN0cmNocihsaW5lLCAnXScpOwogICAgICAgICAgICAgICAgbCsrOwogICAgICAgICAgICAgICAgcD10bXA7CiAgICAgICAgICAgICAgICB3aGlsZShJU1cobCkpIGwrKzsKICAgICAgICAgICAgICAgIHdoaWxlKCpsICE9ICc7JykgKnArKz0qbCsrOwogICAgICAgICAgICAgICAgKnA9J1wwJzsKICAgICAgICAgICAgICAgIGZvcihpbnQgaT1zOyBpPD1lOyBpKyspewogICAgICAgICAgICAgICAgICAgIHNwcmludGYoY2lyY3VpdFBvcnRzW3BvcnRDb3VudF0ubmFtZSwgIiVzWyVkXSIsdG1wLGkpOwogICAgICAgICAgICAgICAgICAgIGlmKCBzdHJzdHIobGluZSwgIm91dHB1dCIpKQogICAgICAgICAgICAgICAgICAgICAgICBjaXJjdWl0UG9ydHNbcG9ydENvdW50XS5kaXIgPSAwOwogICAgICAgICAgICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICAgICAgICAgICAgY2lyY3VpdFBvcnRzW3BvcnRDb3VudF0uZGlyID0gMTsKICAgICAgICAgICAgICAgICAgICBjaXJjdWl0UG9ydHNbcG9ydENvdW50XS5pc0J1cyA9IDE7CiAgICAgICAgICAgICAgICAgICAgcG9ydENvdW50Kys7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICBjaXJjdWl0UG9ydHNbcG9ydENvdW50XS5pc0J1cyA9IDA7CiAgICAgICAgICAgICAgICBsID0gc3Ryc3RyKGxpbmUsICJwdXQiKTsKICAgICAgICAgICAgICAgIC8vaWYobD09TlVMTCkKICAgICAgICAgICAgICAgIC8vbD1saW5lOwogICAgICAgICAgICAgICAgbCs9MzsKICAgICAgICAgICAgICAgIHA9dG1wOwogICAgICAgICAgICAgICAgd2hpbGUoSVNXKGwpKSBsKys7CiAgICAgICAgICAgICAgICB3aGlsZSgqbCAhPSAnOycpICpwKys9KmwrKzsKICAgICAgICAgICAgICAgICpwPSdcMCc7CiAgICAgICAgICAgICAgICBzdHJjcHkoY2lyY3VpdFBvcnRzW3BvcnRDb3VudF0ubmFtZSwgdG1wKTsKICAgICAgICAgICAgICAgIC8vY2lyY3VpdFBvcnRzW3BvcnRDb3VudF0uZGlyID0gMTsKICAgICAgICAgICAgICAgIGlmKCBzdHJzdHIobGluZSwgIm91dHB1dCIpKQogICAgICAgICAgICAgICAgICAgIGNpcmN1aXRQb3J0c1twb3J0Q291bnRdLmRpciA9IDA7CiAgICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICAgICAgY2lyY3VpdFBvcnRzW3BvcnRDb3VudF0uZGlyID0gMTsKICAgICAgICAgICAgICAgIHBvcnRDb3VudCsrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgIH0KICAgIH0KfQoKLyogTElTVCAqLwp0eXBlZGVmIHN0cnVjdCB7aW50IGNvdW50OyBjaGFyIGl0ZW1zWzI1Nl1bMzJdO30gU0xJU1Q7ClNMSVNUICogbHN0TmV3KCl7CiAgICAKICAgIFNMSVNUICpsID0gKFNMSVNUICopIG1hbGxvYyAoc2l6ZW9mKFNMSVNUKSk7CiAgICBsLT5jb3VudCA9IDA7CiAgICByZXR1cm4gbDsKfQppbnQgbHN0QWRkKFNMSVNUICpsc3QsIGNoYXIgaXRlbVszMl0pewogICAgc3RyY3B5KGxzdC0+aXRlbXNbbHN0LT5jb3VudF0sIGl0ZW0pOwogICAgbHN0LT5jb3VudCsrOwogICAgcmV0dXJuIChsc3QtPmNvdW50KS0xOwp9CmludCBsc3RGaW5kKFNMSVNUICpsc3QsIGNoYXIgaXRlbVszMl0pewogICAgaW50IGk7CiAgICBmb3IoaT0wOyBpPChsc3QtPmNvdW50KTsgaSsrKQogICAgICAgIGlmKCFzdHJjbXAobHN0LT5pdGVtc1tpXSxpdGVtKSkgcmV0dXJuIGk7CiAgICByZXR1cm4gLTE7Cn0KCmludCBsc3RGaW5kQWRkKFNMSVNUICpsc3QsIGNoYXIgaXRlbVszMl0pewogICAgaW50IHggPSBsc3RGaW5kKGxzdCwgaXRlbSk7CiAgICBpZigoeD4tMSkpCiAgICAgICAgcmV0dXJuIHg7CiAgICBlbHNlCiAgICAgICAgcmV0dXJuIGxzdEFkZChsc3QsaXRlbSk7Cn0KLyogKi8KCgojZGVmaW5lICAgICBTQ0xfQ09VTlQgICAyNTYKaW50IGR1bXBHYXRlcygpCnsKICAgIGludCBpLCBlLCBmOwogICAgaW50IHN0YXRzW1NDTF9DT1VOVF0sIGFyZWFzW1NDTF9DT1VOVF07CiAgICBpbnQgYXJlYSA9IDA7CiAgICBTTElTVCAqY2VsbHM7CiAgICBjZWxscyA9IGxzdE5ldygpOwogICAgCiAgICBmb3IoZT0wOyBlPFNDTF9DT1VOVDsgZSsrKSB7c3RhdHNbZV09MDthcmVhc1tlXT0wO30KICAgIAogICAgZm9yKGk9MDsgaTxnQ291bnQ7IGkrKykgewogICAgICAgIC8vcHJpbnRmKCIlZDogJXNcbiIsIGksIGNpcmN1aXRHYXRlc1tpXS50eXBlKTsKICAgICAgICBpZihzdHJzdHIoIGNpcmN1aXRHYXRlc1tpXS50eXBlLCJfRExBVENIX1BfIikpewogICAgICAgICAgICBwcmludGYoIkRlc2lnbiBFeGNlcHRpb246IFRoZSBkZXNpZ24gaW5mZXJzIGEgbGF0Y2ghIEluc3RhdG5jZSBuYW1lOiAlc1xuIiwgIGNpcmN1aXRHYXRlc1tpXS5uYW1lKTsKICAgICAgICAgICAgZXhpdCgtMTAwKTsKICAgICAgICB9CiAgICAgICAgZiA9IGxzdEZpbmRBZGQoY2VsbHMsIGNpcmN1aXRHYXRlc1tpXS50eXBlKTsKICAgICAgICBzdGF0c1tmXSsrOwogICAgICAgIGFyZWFzW2ZdICs9IGRvY1siY2VsbHMiXVtjaXJjdWl0R2F0ZXNbaV0udHlwZV1bImFyZWEiXS5HZXRJbnQoKTsKICAgICAgICBhcmVhID0gYXJlYSArIGRvY1siY2VsbHMiXVtjaXJjdWl0R2F0ZXNbaV0udHlwZV1bImFyZWEiXS5HZXRJbnQoKTsKICAgIH0KICAgIAogICAgLyoKICAgICBmb3IoaT0wOyBpPGdDb3VudDsgaSsrKXsKICAgICAvL3ByaW50ZigiSlNPTiA6ICVkXG4iLCBkb2NbImNlbGxzIl1bY2lyY3VpdEdhdGVzW2ldLnR5cGVdWyJhcmVhIl0uR2V0SW50KCkpOwogICAgIGFyZWEgPSBhcmVhICsgZG9jWyJjZWxscyJdW2NpcmN1aXRHYXRlc1tpXS50eXBlXVsiYXJlYSJdLkdldEludCgpOwogICAgIGZvcihlPTA7IGU8Q0NPVU5UOyBlKyspCiAgICAgaWYoc3Ryc3RyKGNpcmN1aXRHYXRlc1tpXS50eXBlLGNlbGxzUHJlZml4W2VdKSkgewogICAgIHN0YXRzW2VdKys7CiAgICAgYnJlYWs7CiAgICAgfQogICAgIH0KICAgICAqLwogICAgZm9yKGU9MDsgZTxjZWxscy0+Y291bnQ7IGUrKykgewogICAgICAgIHByaW50ZigiJXNcdENvdW50OiVkLCBBcmVhOiAlZFxuIiwgY2VsbHMtPml0ZW1zW2VdLCBzdGF0c1tlXSwgYXJlYXNbZV0pOwogICAgfQogICAgcHJpbnRmKCJUb3RhbCBDZWxsIEFyZWE6ICVkIFxuIiwgYXJlYSk7CiAgICBwcmludGYoIkVxdWl2YWxlbnQgTkFORDJ4MSBHYXRlcyBjb3VudDogJWRcbiIsYXJlYS9kb2NbImNlbGxzIl1bIk5BTkQyWDEiXVsiYXJlYSJdLkdldEludCgpKTsKICAgIAp9CgovKgogaW50IGdldEZPKGludCBnLCBpbnQgZm9bXSl7CiBpbnQgZm9jID0gMDsKIGludCBpOwogCiBmb3IoaT0wOyBpPGdDb3VudDsgaSsrKSB7CiBpZighc3RyY21wKGNpcmN1aXRHYXRlc1tnXS5waW5zW10pKQogfQogCiAKIH0KICovCgppbnQgbG9hZFNDTChjaGFyICpmbikKewogICAgaW50IHNpemU7CiAgICBjaGFyIHRtcFszMl07CiAgICBGSUxFKiBmcCA9IGZvcGVuKGZuLCAiciIpOyAvLyBub24tV2luZG93cyB1c2UgInIiCiAgICBmc2VlayhmcCwgMCwgU0VFS19FTkQpOyAvLyBzZWVrIHRvIGVuZCBvZiBmaWxlCiAgICBzaXplID0gZnRlbGwoZnApOyAvLyBnZXQgY3VycmVudCBmaWxlIHBvaW50ZXIKICAgIGZzZWVrKGZwLCAwLCBTRUVLX1NFVCk7IC8vIHNlZWsgYmFjayB0byBiZWdpbm5pbmcgb2YgZmlsZQogICAgCiAgICBjaGFyICpyZWFkQnVmZmVyID0gKGNoYXIgKikgbWFsbG9jKHNpemUpOwogICAgCiAgICBGaWxlUmVhZFN0cmVhbSBpcyhmcCwgcmVhZEJ1ZmZlciwgc2l6ZSk7CiAgICBkb2MuUGFyc2VTdHJlYW0oaXMpOwogICAgCiAgICAvL3ByaW50ZigiXG5KU09OIDogJWRcbiIsIGRvY1siY2VsbHMiXVsiQU5EMlgxIl1bImFyZWEiXS5HZXRJbnQoKSk7CiAgICAKICAgIGZvciAoVmFsdWU6OkNvbnN0TWVtYmVySXRlcmF0b3IgaXRyID0gZG9jWyJjZWxscyJdLk1lbWJlckJlZ2luKCk7CiAgICAgICAgIGl0ciAhPSBkb2NbImNlbGxzIl0uTWVtYmVyRW5kKCk7ICsraXRyKQogICAgewogICAgICAgIHN0cmNweSh0bXAsIGl0ci0+bmFtZS5HZXRTdHJpbmcoKSk7CiAgICAgICAgaWYoIXN0cmNtcCh0bXAsImlucHV0IikpIGNvbnRpbnVlOwogICAgICAgIGlmKCFzdHJjbXAodG1wLCJvdXRwdXQiKSkgY29udGludWU7CiAgICAgICAgaWYoIXN0cmNtcCh0bXAsImduZCIpKSBjb250aW51ZTsKICAgICAgICBpZighc3RyY21wKHRtcCwidmRkIikpIGNvbnRpbnVlOwogICAgICAgIHN0cmNweShjZWxsc1ByZWZpeFtDQ09VTlRdLHRtcCk7CiAgICAgICAgQ0NPVU5UKys7CiAgICAgICAgCiAgICAgICAgcHJpbnRmKCJUeXBlIG9mIG1lbWJlciAlcyAlc1xuIiwgaXRyLT5uYW1lLkdldFN0cmluZygpLGNlbGxzUHJlZml4W0NDT1VOVC0xXSk7CiAgICB9CiAgICAKICAgIGZjbG9zZShmcCk7Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyICphcmd2W10pIHsKICAgIEZJTEUgKmZwOwogICAgCiAgICBsb2FkU0NMKCJvc3UzNTAuanNvbiIpOwogICAgCiAgICBpZigoZnA9Zm9wZW4oYXJndlsxXSwiciIpKSE9TlVMTCl7CiAgICAgICAgcGFyc2VHTFYoZnApOwogICAgfQogICAgZHVtcEdhdGVzKCk7CiAgICBwcmludGYoInRvdGFsIG51bWJlciBvZiBjZWxsczogJWQgKCVkIEZsaXAgRkxvcHMpXG5Ub3RhbCBudW1iZXIgb2YgbmV0czogJWRcblRvdGFsIG51bWJlciBvZiBwb3J0czogJWRcbiIsIGdDb3VudCwgZmZDb3VudCwgbkNvdW50LCBwb3J0Q291bnQpOwogICAgCiAgICBmY2xvc2UoZnApOwogICAgCiAgICAvL2xvYWRTQ0woIm9zdTM1MC5qc29uIik7CiAgICAKICAgIHJldHVybiAwOwp9ClNoYXJpbmcgc2V0dGluZ3MK