qdoc.cpp


/* \file qdoc.cpp
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <string>
using namespace std;
#include "strtoken.h"

const int MAX_FILES = 32;

//! documents Quartus Verilog projects
class qdoc {
public:
	qdoc() { };
	~qdoc() { };
	void read_qsf(FILE *in);
	void read_cfg(FILE *in, FILE *out);
	void parse_insert(char *str, FILE *out);
	void print();
	void verilog_contents(FILE *out);
	void quartus_contents(FILE *out);
	void swap_toplevel();
	void verilog_print(FILE *out, string filename);
	void quartus_print(FILE *out, string suffix);
	string projname;
	string family,device,date,quartus_version;
	string toplevel;
	string verilog_file[MAX_FILES];
	string quartus_file[MAX_FILES];
	int nfiles, nqfiles;
};

void transcribe(FILE *in, FILE *out);

int main(int argc, char *argv[])
{
	qdoc doc;
	FILE *in, *out;
	errno_t nerr;
	if (argc<2) {
		cout << "usage: qdoc projname [config_file]\n";
		cout << "default config_file is \"qdoc.cfg.html\"\n";
		return EXIT_FAILURE;
	}
	// open project qsf file
	doc.projname = argv[1];
	string filename = doc.projname + ".qsf";
	nerr = fopen_s(&in,filename.c_str(),"r");
	if (nerr) {
		cout << "file: " << filename << " not found\n";
		return EXIT_FAILURE;
	}
	doc.read_qsf(in);
	doc.swap_toplevel();
	fclose(in);
	// open output configuration file
	filename = (argc>2? argv[2]: "qdoc.cfg.html");
	nerr = fopen_s(&in,filename.c_str(),"r");
	if (nerr) {
		cout << "file: " << filename << " not found\n";
		return EXIT_FAILURE;
	}
	// open output file
	filename = doc.projname + ".html";
	nerr = fopen_s(&out,filename.c_str(),"w");
	if (nerr) {
		cout << "error opening " << filename << endl;
	}
	doc.read_cfg(in, out);
	fclose(in);
	fclose(out);
	doc.print();
	return EXIT_SUCCESS;
}

void qdoc::read_qsf(FILE *in)
{
	char buf[512];
	char *inp, *token;
	bool done = false;
	int lines = 0;
	nfiles = 0;
	while (!done) {
		fgets(buf,511,in);
		if (feof(in)) return;
		lines++;
		strtrm(buf,'\n'); // terminate at newline character
		strtrm(buf,'#'); // terminate at comment character
		inp = buf;
		string tok;
		int state = 0;
		while ((token=strtoken(inp,' '))!=0) {
			tok = token;
			if (state==0) {
				if (tok.compare("set_global_assignment")!=0) break;
				state = 1;
			}
			else if (state==1) {
				if (tok.compare("-name")!=0) break;
				state = 2;
			}
			else if (state==2) {
				strqtrm(inp,' ');
				if (!inp) break;
				if (tok.compare("FAMILY")==0) family = inp;
				else if (tok.compare("DEVICE")==0) device = inp;
				else if (tok.compare("TOP_LEVEL_ENTITY")==0) toplevel = inp;
				else if (tok.compare("PROJECT_CREATION_TIME_DATE")==0)
					date = inp;
				else if (tok.compare("LAST_QUARTUS_VERSION")==0)
					 quartus_version = inp;
				else if (tok.compare("VERILOG_FILE")==0) 
					verilog_file[nfiles++] = inp;
				state = 0;
				break;
			}
		}
	}
}

void qdoc::swap_toplevel() {
	string filename = toplevel + ".v";
	int found = -1;
	for (int i=0; i<nfiles; i++) {
		if (filename.compare(verilog_file[i])==0) {
			found = i;
			break;
		}
	}
	if (found) {
		string tmp = verilog_file[0];
		verilog_file[0] = verilog_file[found];
		verilog_file[found] = tmp;
	}
}


void qdoc::print() {
	cout << "Family: " << family  << endl;
	cout << "Device: " << device  << endl;
	cout << "Quartus "<< quartus_version << endl;
	cout << "date " << date << endl;
	cout << "top level entity " << toplevel << endl;
	if (nfiles) cout << nfiles << " verilog files\n";
	if (nqfiles) cout << nqfiles << " quartus files\n";
}

void qdoc::verilog_contents(FILE *out)
{
	for (int i=0; i<nfiles; i++) {
		fputs("<a href=\"#",out);
		fputs(verilog_file[i].c_str(),out);
		fputs("\">",out);
		fputs(verilog_file[i].c_str(),out);
		fputs("</a><br>\n",out);
	}
}

void qdoc::verilog_print(FILE *out, string filename)
{
	FILE *in;
	errno_t nerr = fopen_s(&in,filename.c_str(),"r");
	if (nerr) {
		cout << "file not found: " << filename << endl;
		return;
	}

	fputs("<a name=\"",out);
	fputs(filename.c_str(),out);
	fputs("\">\n\n",out);
	fputs("<h3><code>",out);
	fputs(filename.c_str(),out);
	fputs("</code></h3>\n",out);
	transcribe(in,out);
	fclose(in);
}
	
void qdoc::read_cfg(FILE *in, FILE *out)
{
	char buf[512];
	char *inp, *next, *html;
	bool done = false;
	nqfiles = 0;
	/*
	 * Go through input file, line by line
	 */
	while (!done) {
		fgets(buf,511,in);
		if (feof(in)) break;
		next = buf;
		/*
		 * parse current line
		 */
		while (next) {
			/*
			 * search for '<', and copy prior text to
			 * output stream
			 */
			inp = next;
			next = strqtrm(inp,'<');
			if (*inp) fputs(inp,out);
			/*
			 * next points to character after '<' (if '<'
			 * was found).
			 */
			if (next) {
				/*
				*  isolate (in html) text up to the character '>'
				*/
				html = next;
				next = strqtrm(html,'>');
				/*
				*  check for known codes
				*/
				string token = html;
				char *value = strqtrm(html,' ');
				if (token.substr(0,7).compare("include")==0) {
					quartus_file[nqfiles++] = value;
					//cout << "quartus_file: " << quartus_file[nqfiles-1] << endl;
					continue; // go to next line
				}
				else if (token.substr(0,6).compare("insert")==0) {
					parse_insert(value,out);
				}
				/*
				 *  otherwise just echo the html code
				 */
				else fprintf(out,"<%s>",token.c_str());
			}
		}
	}
}

void insert_date(FILE *out)
{
	char buf[32];
	time_t ltime;
	errno_t nerr;
	time( &ltime );
	nerr = ctime_s(buf,30,&ltime);
	int nchar = strlen(buf);
	buf[nchar-1] = 0;
	fputs(buf,out);
}

void qdoc::parse_insert(char *str, FILE *out)
{
	string tok = str; //strtoken(str,' ');
	if (tok.compare("projname")==0) fputs(projname.c_str(),out);
	else if (tok.compare("date")==0) insert_date(out);
	else if (tok.compare("verilog_contents")==0) verilog_contents(out);
	else if (tok.compare("quartus_contents")==0) quartus_contents(out);
	else if (tok.compare("verilog")==0) {
		for (int i=0; i<nfiles; i++) verilog_print(out,verilog_file[i]);
	}
	else if (tok.compare("quartus")==0) {
		for (int i=0; i<nqfiles; i++) quartus_print(out,quartus_file[i]);
	}
	else 	cout << "insert: " << tok << endl;

}


void qdoc::quartus_contents(FILE *out)
{
	for (int i=0; i<nqfiles; i++) {
		fputs("<a href=\"#",out);
		fputs(quartus_file[i].c_str(),out);
		fputs("\">",out);
		fputs(quartus_file[i].c_str(),out);
		fputs("</a><br>\n",out);
	}
}

void qdoc::quartus_print(FILE *out, string suffix)
{
	FILE *in;
	string filename = projname + "." + suffix;
	errno_t nerr = fopen_s(&in,filename.c_str(),"r");
	if (nerr) {
		cout << "file not found: " << filename << endl;
		return;
	}
	// anchor definition
	fputs("<a name=\"",out);
	fputs(suffix.c_str(),out);
	fputs("\">\n\n",out);
	// section header
	fputs("<h3><code>",out);
	fputs(suffix.c_str(),out);
	fputs("</code></h3>\n",out);
	transcribe(in,out);
	fclose(in);
}

void transcribe(FILE *in, FILE *out)
{
	char ch;
	bool done = false;
	fputs("<p><pre>\n",out);
	while (!done) {
		ch = (char) fgetc(in);
		if (feof(in)) break;
		if (ch=='<') fputs("&lt;",out);
		else if (ch=='>') fputs("&gt;",out);
		else if (ch=='&') fputs("&amp;",out);
		else if (ch=='\t') fputs("    ",out);
		else fputc(ch,out);
	}
	fputs("</pre>\n",out);
	fclose(in);
}

/*
   set_global_assignment -name FAMILY "Cyclone II"
   set_global_assignment -name DEVICE EP2C35F672C6
   set_global_assignment -name TOP_LEVEL_ENTITY de2lab1
   set_global_assignment -name ORIGINAL_QUARTUS_VERSION 6.0
   set_global_assignment -name PROJECT_CREATION_TIME_DATE "15:49:53  JANUARY 16, 2007"
   set_global_assignment -name LAST_QUARTUS_VERSION 6.0
   set_global_assignment -name VERILOG_FILE hex_7seg.v
*/
		
		


Results




Maintained by John Loomis, updated Thu Jan 18 11:04:13 2007