Back to index

lshw  02.16
print.cc
Go to the documentation of this file.
00001 /*
00002  * print.cc
00003  *
00004  * This module prints out the hardware tree depending on options passed
00005  * Output can be plain text (good for human beings), HTML (good for web brow-
00006  * sers), XML (good for programs) or "hardware path" (ioscan-like).
00007  *
00008  */
00009 
00010 #include "print.h"
00011 #include "options.h"
00012 #include "version.h"
00013 #include "osutils.h"
00014 #include "config.h"
00015 #include <cstring>
00016 #include <iostream>
00017 #include <sstream>
00018 #include <iomanip>
00019 #include <unistd.h>
00020 #include <stdlib.h>
00021 #include <stdio.h>
00022 #include <sys/ioctl.h>
00023 #include <termios.h>
00024 
00025 __ID("@(#) $Id: print.cc 2433 2012-01-10 22:01:30Z lyonel $");
00026 
00027 static unsigned int columns = 0, rows = 0;
00028 
00029 static void init_wsize()
00030 {
00031   struct winsize ws;
00032   char *env;
00033 
00034   if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws))
00035   {
00036     rows = ws.ws_row;
00037     columns = ws.ws_col;
00038   }
00039 
00040   if (!rows)
00041   {
00042     env = getenv("LINES");
00043     if (env)
00044       rows = atoi(env);
00045     if (!rows)
00046       rows = 24;
00047   }
00048 
00049   if (!columns)
00050   {
00051     env = getenv("COLUMNS");
00052     if (env)
00053       columns = atoi(env);
00054     if (!columns)
00055       columns = 80;
00056   }
00057 }
00058 
00059 
00060 static void tab(int level,
00061 bool connect = true)
00062 {
00063   if (level <= 0)
00064     return;
00065   for (int i = 0; i < level - 1; i++)
00066     cout << "   ";
00067   cout << "  ";
00068   if (connect)
00069     cout << "*-";
00070   else
00071     cout << "  ";
00072 }
00073 
00074 void print(hwNode & node,
00075 bool html,
00076 int level)
00077 {
00078   vector < string > config;
00079   vector < string > resources;
00080   if (html)
00081     config = node.getConfigValues("</td><td>=</td><td>");
00082   else
00083     config = node.getConfigValues("=");
00084   if (html)
00085     resources = node.getResources("</td><td>:</td><td>");
00086   else
00087     resources = node.getResources(":");
00088 
00089   if (html && (level == 0))
00090   {
00091     cout <<
00092       "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" <<
00093       endl;
00094     cout << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
00095     cout << "<head>" << endl;
00096     cout << "<meta name=\"generator\" " <<
00097       " content=\"lshw-" << getpackageversion() << "\" />" << endl;
00098     cout << "<style type=\"text/css\">" << endl;
00099     cout << "  .first {font-weight: bold; margin-left: none; padding-right: 1em;vertical-align: top; }" << endl;
00100     cout << "  .second {padding-left: 1em; width: 100%; vertical-align: center; }" << endl;
00101     cout << "  .id {font-family: monospace;}" << endl;
00102     cout << "  .indented {margin-left: 2em; border-left: dotted thin #dde; padding-bottom: 1em; }" << endl;
00103     cout << "  .node {border: solid thin #ffcc66; padding: 1em; background: #ffffcc; }" << endl;
00104     cout << "  .node-unclaimed {border: dotted thin #c3c3c3; padding: 1em; background: #fafafa; color: red; }" << endl;
00105     cout << "  .node-disabled {border: solid thin #f55; padding: 1em; background: #fee; color: gray; }" << endl;
00106     cout << "</style>" << endl;
00107 
00108     cout << "<title>";
00109     cout << node.getId();
00110     cout << "</title>" << endl;
00111     cout << "</head>" << endl;
00112     cout << "<body>" << endl;
00113   }
00114 
00115   if (visible(node.getClassName()))
00116   {
00117     tab(level, !html);
00118 
00119     if (html)
00120     {
00121       tab(level, false);
00122       cout << "<div class=\"indented\">" << endl;
00123       tab(level, false);
00124       cout << "<table width=\"100%\" class=\"node";
00125       if(!node.claimed())
00126         cout << "-unclaimed";
00127       else
00128       {
00129         if(node.disabled())
00130           cout << "-disabled";
00131       }
00132       cout << "\" summary=\"attributes of " << node.getId() << "\">" << endl;
00133     }
00134 
00135     if (html)
00136       cout << " <thead><tr><td class=\"first\">id:</td><td class=\"second\"><div class=\"id\">";
00137     cout << node.getId();
00138     if (html)
00139       cout << "</div>";
00140     else
00141     {
00142       if (node.disabled())
00143         cout << _(" DISABLED");
00144       if (!node.claimed())
00145         cout << _(" UNCLAIMED");
00146     }
00147     if (html)
00148       cout << "</td></tr></thead>";
00149     cout << endl;
00150 
00151 #if 0
00152     if (node.getHandle() != "")
00153     {
00154       tab(level + 1, false);
00155       if (html)
00156         cout << "<tr><td class=\"first\">";
00157       cout << "handle: ";
00158       if (html)
00159         cout << "</td><td class=\"second\">";
00160       cout << node.getHandle();
00161       if (html)
00162         cout << "</td></tr>";
00163       cout << endl;
00164     }
00165 #endif
00166 
00167     if (html)
00168       cout << " <tbody>" << endl;
00169 
00170     if (node.getDescription() != "")
00171     {
00172       tab(level + 1, false);
00173       if (html)
00174         cout << "<tr><td class=\"first\">";
00175       cout << _("description") << ": ";
00176       if (html)
00177         cout << "</td><td class=\"second\">";
00178       cout << node.getDescription();
00179       if (html)
00180         cout << "</td></tr>";
00181       cout << endl;
00182     }
00183 
00184     if (node.getProduct() != "")
00185     {
00186       tab(level + 1, false);
00187       if (html)
00188         cout << "<tr><td class=\"first\">";
00189       cout << _("product") << ": ";
00190       if (html)
00191         cout << "</td><td class=\"second\">";
00192       cout << node.getProduct();
00193       if (html)
00194         cout << "</td></tr>";
00195       cout << endl;
00196     }
00197 
00198     if (node.getVendor() != "")
00199     {
00200       tab(level + 1, false);
00201       if (html)
00202         cout << "<tr><td class=\"first\">";
00203       cout << _("vendor") << ": ";
00204       if (html)
00205         cout << "</td><td class=\"second\">";
00206       cout << node.getVendor();
00207       if (html)
00208         cout << "</td></tr>";
00209       cout << endl;
00210     }
00211 
00212     if (node.getPhysId() != "")
00213     {
00214       tab(level + 1, false);
00215       if (html)
00216         cout << "<tr><td class=\"first\">";
00217       cout << _("physical id") << ": ";
00218       if (html)
00219         cout << "</td><td class=\"second\"><div class=\"id\">";
00220       cout << node.getPhysId();
00221       if (html)
00222         cout << "</div></td></tr>";
00223       cout << endl;
00224     }
00225 
00226     if (node.getBusInfo() != "")
00227     {
00228       tab(level + 1, false);
00229       if (html)
00230         cout << "<tr><td class=\"first\">";
00231       cout << _("bus info") << ": ";
00232       if (html)
00233         cout << "</td><td class=\"second\"><div class=\"id\">";
00234       cout << node.getBusInfo();
00235       if (html)
00236         cout << "</div></td></tr>";
00237       cout << endl;
00238     }
00239 
00240     if (node.getLogicalName() != "")
00241     {
00242       vector<string> logicalnames = node.getLogicalNames();
00243 
00244       for(unsigned int i = 0; i<logicalnames.size(); i++)
00245       {
00246         tab(level + 1, false);
00247         if (html)
00248           cout << "<tr><td class=\"first\">";
00249         cout << _("logical name") << ": ";
00250         if (html)
00251           cout << "</td><td class=\"second\"><div class=\"id\">";
00252         cout << logicalnames[i];
00253         if (html)
00254           cout << "</div></td></tr>";
00255         cout << endl;
00256       }
00257     }
00258 
00259     if (node.getVersion() != "")
00260     {
00261       tab(level + 1, false);
00262       if (html)
00263         cout << "<tr><td class=\"first\">";
00264       cout << _("version") << ": ";
00265       if (html)
00266         cout << "</td><td class=\"second\">";
00267       cout << node.getVersion();
00268       if (html)
00269         cout << "</td></tr>";
00270       cout << endl;
00271     }
00272 
00273     if (node.getDate() != "")
00274     {
00275       tab(level + 1, false);
00276       if (html)
00277         cout << "<tr><td class=\"first\">";
00278       cout << _("date") << ": ";
00279       if (html)
00280         cout << "</td><td class=\"second\">";
00281       cout << node.getDate();
00282       if (html)
00283         cout << "</td></tr>";
00284       cout << endl;
00285     }
00286 
00287     if (node.getSerial() != "")
00288     {
00289       tab(level + 1, false);
00290       if (html)
00291         cout << "<tr><td class=\"first\">";
00292       cout << _("serial") << ": ";
00293       if (html)
00294         cout << "</td><td class=\"second\">";
00295       cout << (enabled("output:sanitize")?REMOVED:node.getSerial());
00296       if (html)
00297         cout << "</td></tr>";
00298       cout << endl;
00299     }
00300 
00301     if (node.getSlot() != "")
00302     {
00303       tab(level + 1, false);
00304       if (html)
00305         cout << "<tr><td class=\"first\">";
00306       cout << _("slot") << ": ";
00307       if (html)
00308         cout << "</td><td class=\"second\">";
00309       cout << node.getSlot();
00310       if (html)
00311         cout << "</td></tr>";
00312       cout << endl;
00313     }
00314 
00315     if (node.getSize() > 0)
00316     {
00317       tab(level + 1, false);
00318       if (html)
00319         cout << "<tr><td class=\"first\">";
00320       cout << _("size") << ": ";
00321       if (html)
00322         cout << "</td><td class=\"second\">";
00323       switch (node.getClass())
00324       {
00325         case hw::disk:
00326           cout << kilobytes(node.getSize()) << " (" << decimalkilos(node.getSize()) << "B)";
00327           if (html)
00328             cout << "</td></tr>";
00329           break;
00330         case hw::display:
00331         case hw::memory:
00332         case hw::address:
00333         case hw::storage:
00334         case hw::volume:
00335           cout << kilobytes(node.getSize());
00336           if (html)
00337             cout << "</td></tr>";
00338           break;
00339 
00340         case hw::processor:
00341         case hw::bus:
00342         case hw::system:
00343           cout << decimalkilos(node.getSize()) << "Hz";
00344           if (html)
00345             cout << "</td></tr>";
00346           break;
00347 
00348         case hw::network:
00349           cout << decimalkilos(node.getSize()) << "bit/s";
00350           if (html)
00351             cout << "</td></tr>";
00352           break;
00353 
00354         case hw::power:
00355           cout << node.getSize();
00356           cout << "mWh";
00357           if (html)
00358             cout << "</td></tr>";
00359           break;
00360 
00361         default:
00362           cout << node.getSize();
00363           if (html)
00364             cout << "</td></tr>";
00365       }
00366       cout << endl;
00367     }
00368 
00369     if (node.getCapacity() > 0)
00370     {
00371       tab(level + 1, false);
00372       if (html)
00373         cout << "<tr><td class=\"first\">";
00374       cout << _("capacity") << ": ";
00375       if (html)
00376         cout << "</td><td class=\"second\">";
00377       switch (node.getClass())
00378       {
00379         case hw::disk:
00380           cout << kilobytes(node.getCapacity()) << " (" << decimalkilos(node.getCapacity()) << "B)";
00381           if (html)
00382             cout << "</td></tr>";
00383           break;
00384         case hw::memory:
00385         case hw::address:
00386         case hw::storage:
00387         case hw::volume:
00388           cout << kilobytes(node.getCapacity());
00389           if (html)
00390             cout << "</td></tr>";
00391           break;
00392 
00393         case hw::processor:
00394         case hw::bus:
00395         case hw::system:
00396           cout << decimalkilos(node.getCapacity());
00397           cout << "Hz";
00398           if (html)
00399             cout << "</td></tr>";
00400           break;
00401 
00402         case hw::network:
00403           cout << decimalkilos(node.getCapacity());
00404           cout << "bit/s";
00405           if (html)
00406             cout << "</td></tr>";
00407           break;
00408 
00409         case hw::power:
00410           cout << node.getCapacity();
00411           cout << "mWh";
00412           if (html)
00413             cout << "</td></tr>";
00414           break;
00415 
00416         default:
00417           cout << node.getCapacity();
00418           if (html)
00419             cout << "</td></tr>";
00420       }
00421       cout << endl;
00422     }
00423 
00424     if (node.getClass() == hw::address)
00425     {
00426       tab(level + 1, false);
00427       if (html)
00428         cout << "<tr><td class=\"first\">";
00429       if (node.getSize() == 0)
00430         cout << _("address") << ": " << hex << setfill('0') << setw(8) << node.
00431           getStart() << dec;
00432       else
00433         cout << _("range") << ": " << hex << setfill('0') << setw(8) << node.
00434           getStart() << " - " << hex << setfill('0') << setw(8) << node.
00435           getStart() + node.getSize() - 1 << dec;
00436       cout << endl;
00437     }
00438 
00439     if (node.getWidth() > 0)
00440     {
00441       tab(level + 1, false);
00442       if (html)
00443         cout << "<tr><td class=\"first\">";
00444       cout << _("width") << ": ";
00445       if (html)
00446         cout << "</td><td class=\"second\">";
00447       cout << node.getWidth() << " bits";
00448       if (html)
00449         cout << "</td></tr>";
00450       cout << endl;
00451     }
00452 
00453     if (node.getClock() > 0)
00454     {
00455       tab(level + 1, false);
00456       if (html)
00457         cout << "<tr><td class=\"first\">";
00458       cout << _("clock") << ": ";
00459       if (html)
00460         cout << "</td><td class=\"second\">";
00461       cout << decimalkilos(node.getClock());
00462       cout << "Hz";
00463       if (node.getClass() == hw::memory)
00464         cout << " (" << setiosflags(ios::fixed) << setprecision(1) << 1.0e9 / node.getClock() << "ns)";
00465       if (html)
00466         cout << "</td></tr>";
00467       cout << endl;
00468     }
00469 
00470     if (node.getCapabilities() != "")
00471     {
00472       tab(level + 1, false);
00473       if (html)
00474         cout << "<tr><td class=\"first\">";
00475       cout << _("capabilities") << ": ";
00476       if (html)
00477       {
00478         vector < string > capabilities = node.getCapabilitiesList();
00479         cout << "</td><td class=\"second\">";
00480         for(unsigned i=0; i<capabilities.size(); i++)
00481         {
00482           cout << "<dfn title=\"" << escape(node.getCapabilityDescription(capabilities[i])) << "\">" << capabilities[i] << "</dfn> ";
00483         }
00484         cout << "</td></tr>";
00485       }
00486       else
00487         cout << node.getCapabilities();
00488       cout << endl;
00489     }
00490 
00491     if (config.size() > 0)
00492     {
00493       tab(level + 1, false);
00494       if (html)
00495         cout << "<tr><td class=\"first\">";
00496       cout << _("configuration:");
00497       if (html)
00498         cout << "</td><td class=\"second\"><table summary=\"" << _("configuration of ") << node.
00499           getId() << "\">";
00500       for (unsigned int i = 0; i < config.size(); i++)
00501       {
00502         if (html)
00503           cout << "<tr><td class=\"sub-first\">";
00504         cout << " " << config[i];
00505         if (html)
00506           cout << "</td></tr>";
00507       }
00508       if (html)
00509         cout << "</table></td></tr>";
00510       cout << endl;
00511     }
00512 
00513     if (resources.size() > 0)
00514     {
00515       tab(level + 1, false);
00516       if (html)
00517         cout << "<tr><td class=\"first\">";
00518       cout << _("resources:");
00519       if (html)
00520         cout << "</td><td class=\"second\"><table summary=\"" << _("resources of ") << node.
00521           getId() << "\">";
00522       for (unsigned int i = 0; i < resources.size(); i++)
00523       {
00524         if (html)
00525           cout << "<tr><td class=\"sub-first\">";
00526         cout << " " << resources[i];
00527         if (html)
00528           cout << "</td></tr>";
00529       }
00530       if (html)
00531         cout << "</table></td></tr>";
00532       cout << endl;
00533     }
00534 
00535     if (html)
00536       cout << " </tbody>";
00537 
00538     if (html)
00539     {
00540       tab(level, false);
00541       cout << "</table></div>" << endl;
00542     }
00543 
00544   }                                               // if visible
00545 
00546   for (unsigned int i = 0; i < node.countChildren(); i++)
00547   {
00548     if(html)
00549       cout << "<div class=\"indented\">" << endl;
00550     print(*node.getChild(i), html, visible(node.getClassName()) ? level + 1 : 1);
00551     if(html)
00552       cout << "</div>" << endl;
00553   }
00554 
00555   if (html)
00556   {
00557     if (visible(node.getClassName()))
00558     {
00559       tab(level, false);
00560     }
00561     if (level == 0)
00562     {
00563       cout << "</body>" << endl;
00564       cout << "</html>" << endl;
00565     }
00566   }
00567 }
00568 
00569 
00570 struct hwpath
00571 {
00572   string path;
00573   string description;
00574   string devname;
00575   string classname;
00576 };
00577 
00578 static void printhwnode(hwNode & node, vector < hwpath > &l, string prefix = "")
00579 {
00580   hwpath entry;
00581 
00582   entry.path = "";
00583   if (node.getPhysId() != "")
00584     entry.path = prefix + "/" + node.getPhysId();
00585   entry.description = node.asString();
00586   entry.devname = node.getLogicalName();
00587   entry.classname = node.getClassName();
00588 
00589   l.push_back(entry);
00590   for (unsigned int i = 0; i < node.countChildren(); i++)
00591   {
00592     printhwnode(*node.getChild(i), l, entry.path);
00593   }
00594 }
00595 
00596 
00597 static void printbusinfo(hwNode & node, vector < hwpath > &l)
00598 {
00599   hwpath entry;
00600 
00601   entry.path = "";
00602   if (node.getBusInfo() != "")
00603     entry.path = node.getBusInfo();
00604   entry.description = node.asString();
00605   entry.devname = node.getLogicalName();
00606   entry.classname = node.getClassName();
00607   
00608   l.push_back(entry); 
00609   for (unsigned int i = 0; i < node.countChildren(); i++)
00610   { 
00611     printbusinfo(*node.getChild(i), l);
00612   }
00613 }
00614 
00615 static void printline(ostringstream & out)
00616 {
00617   string s = out.str();
00618 
00619   if(isatty(STDOUT_FILENO) && (s.length()>columns))
00620     s.erase(columns);
00621   cout << s << endl;
00622   out.str("");
00623 }
00624 
00625 
00626 static void printincolumns( vector < hwpath > &l, const char *cols[])
00627 {
00628   unsigned int l1 = strlen(_(cols[0])),
00629     l2 = strlen(_(cols[1])),
00630     l3 = strlen(_(cols[2]));
00631   unsigned int i = 0;
00632   ostringstream out;
00633 
00634   for (i = 0; i < l.size(); i++)
00635   {
00636     if (l1 < l[i].path.length())
00637       l1 = l[i].path.length();
00638     if (l2 < l[i].devname.length())
00639       l2 = l[i].devname.length();
00640     if (l3 < l[i].classname.length())
00641       l3 = l[i].classname.length();
00642   }
00643 
00644   out << _(cols[0]);
00645   out << spaces(2 + l1 - strlen(_(cols[0])));
00646   out << _(cols[1]);
00647   out << spaces(2 + l2 - strlen(_(cols[1])));
00648   out << _(cols[2]);
00649   out << spaces(2 + l3 - strlen(_(cols[2])));
00650   out << _(cols[3]);
00651   printline(out);
00652 
00653   out << spaces(l1 + l2 + l3 + strlen(_(cols[3])) + 6, "=");
00654   printline(out);
00655 
00656   for (i = 0; i < l.size(); i++)
00657     if (visible(l[i].classname.c_str()))
00658   {
00659     out << l[i].path;
00660     out << spaces(2 + l1 - l[i].path.length());
00661     out << l[i].devname;
00662     out << spaces(2 + l2 - l[i].devname.length());
00663     out << l[i].classname;
00664     out << spaces(2 + l3 - l[i].classname.length());
00665     out << l[i].description;
00666     printline(out);
00667   }
00668 }
00669 
00670 
00671 static const char *hwpathcols[] =
00672 {
00673   N_("H/W path"),
00674   N_("Device"),
00675   N_("Class"),
00676   N_("Description")
00677 };
00678 
00679 void printhwpath(hwNode & node)
00680 {
00681   vector < hwpath > l;
00682   printhwnode(node, l);
00683   init_wsize();
00684   printincolumns(l, hwpathcols);
00685 }
00686 
00687 
00688 static const char *businfocols[] =
00689 {
00690   N_("Bus info"),
00691   N_("Device"),
00692   N_("Class"),
00693   N_("Description")
00694 };
00695 
00696 void printbusinfo(hwNode & node)
00697 {
00698   vector < hwpath > l;
00699   printbusinfo(node, l);
00700   init_wsize();
00701   printincolumns(l, businfocols);
00702 }