+
+ /**
+ * 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;
+ }