namespace mdref;
+use function feof;
+use function fgets;
+use function fopen;
+use function fseek;
+use function strncmp;
+use function substr;
+use const SEEK_SET;
+
/**
* A ref entry file
*/
* @var resource
*/
private $fd;
-
+
/**
* Open the file
+ *
* @param string $path
+ * @throws Exception
*/
- public function __construct($path) {
- $this->fd = fopen($path, "rb");
+ public function __construct(string $path) {
+ if (!$this->fd = fopen($path, "rb")) {
+ throw Exception::fromLastError();
+ }
}
-
+
/**
* Read the title of the refentry
+ *
* @return string
+ * @throws Exception
*/
- public function readTitle() {
- if (0 === fseek($this->fd, 1, SEEK_SET)) {
+ public function readTitle() : string {
+ if ($this->rewind(1)) {
return fgets($this->fd);
}
+ throw Exception::fromLastError();
}
-
+
/**
- * Read the description of the refentry
+ * Read the description (first line) of the refentry
+ *
* @return string
+ * @throws Exception
*/
- public function readDescription() {
- if (0 === fseek($this->fd, 0, SEEK_SET)
- && (false !== fgets($this->fd))
+ public function readDescription() : string {
+ if (!$this->rewind()) {
+ throw Exception::fromLastError();
+ }
+ if (false !== fgets($this->fd)
&& (false !== fgets($this->fd))) {
return fgets($this->fd);
}
+ return "";
}
-
+
+ /**
+ * Read the full description (first section) of the refentry
+ *
+ * @return string
+ * @throws Exception
+ */
+ public function readFullDescription() : string {
+ $desc = $this->readDescription();
+ while (false !== ($line = fgets($this->fd))) {
+ if ($line[0] === "#") {
+ break;
+ } else {
+ $desc .= $line;
+ }
+ }
+ return $desc;
+ }
+
/**
* Read the first subsection of a global refentry
* @return string
*/
- public function readIntro() {
+ public function readIntro() : string {
$intro = "";
- if (0 === fseek($this->fd, 0, SEEK_SET)) {
+ if ($this->rewind()) {
$header = false;
-
+
while (!feof($this->fd)) {
if (false === ($line = fgets($this->fd))) {
break;
}
/* search first header and read until next header*/
- if ("## " === substr($line, 0, 3)) {
+ if ($this->isHeading($line)) {
if ($header) {
break;
} else {
}
return $intro;
}
+
+ /**
+ * Read section of $title
+ *
+ * @param $title
+ * @return string
+ */
+ public function readSection(string $title) : string {
+ $section = "";
+ if ($this->rewind()) {
+ while (!feof($this->fd)) {
+ if (false === ($line = fgets($this->fd))) {
+ break;
+ }
+ /* search for heading with $title and read until next heading */
+ if ($this->isHeading($line, $title)) {
+ do {
+ if (false === $line = fgets($this->fd)) {
+ break;
+ }
+ if ($this->isHeading($line)) {
+ break;
+ }
+ $section .= $line;
+ } while (true);
+ }
+ }
+ }
+ return $section;
+ }
+
+ /**
+ * @param int $offset
+ * @return bool
+ */
+ private function rewind(int $offset = 0) : bool {
+ return 0 === fseek($this->fd, $offset, SEEK_SET);
+ }
+
+ /**
+ * @param string $line
+ * @param string $title
+ * @return bool
+ */
+ private function isHeading(string $line, ?string $title = null) : bool {
+ if ("## " !== substr($line, 0, 3)) {
+ return false;
+ }
+ if (isset($title)) {
+ return !strncmp(substr($line, 3), $title, strlen($title));
+ }
+ return true;
+ }
}