28 public function __construct(string $path) {
29 if (!$this->fd
= fopen($path, "rb")) {
30 throw Exception
::fromLastError();
35 * Read the title of the refentry
40 public function readTitle() : string {
41 if ($this->rewind(1)) {
42 return fgets($this->fd
);
44 throw Exception
::fromLastError();
48 * Read the description (first line) of the refentry
53 public function readDescription() : string {
54 if (!$this->rewind()) {
55 throw Exception
::fromLastError();
57 if (false !== fgets($this->fd
)
58 && (false !== fgets($this->fd
))) {
59 return fgets($this->fd
);
65 * Read the full description (first section) of the refentry
70 public function readFullDescription() : string {
71 $desc = $this->readDescription();
72 while (false !== ($line = fgets($this->fd
))) {
73 if ($line[0] === "#") {
83 * Read the first subsection of a global refentry
86 public function readIntro() : string {
88 if ($this->rewind()) {
91 while (!feof($this->fd
)) {
92 if (false === ($line = fgets($this->fd
))) {
95 /* search first header and read until next header*/
96 if ($this->isHeading($line)) {
113 * Read section of $title
118 public function readSection(string $title) : string {
120 if ($this->rewind()) {
121 while (!feof($this->fd
)) {
122 if (false === ($line = fgets($this->fd
))) {
125 /* search for heading with $title and read until next heading */
126 if ($this->isHeading($line, $title)) {
128 if (false === $line = fgets($this->fd
)) {
131 if ($this->isHeading($line)) {
146 private function rewind(int $offset = 0) : bool {
147 return 0 === fseek($this->fd
, $offset, SEEK_SET
);
151 * @param string $line
152 * @param string $title
155 private function isHeading(string $line, ?
string $title = null) : bool {
156 if ("## " !== substr($line, 0, 3)) {
160 return !strncmp(substr($line, 3), $title, strlen($title));