<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "language.dtd"
[
	<!-- Identifier with M4 Arg. or variables -->
	<!ENTITY charIden         "(\$[@#]|[\w\-\$\*\{\}&#037;])">
	<!ENTITY simpleIdentifier "(\$[@#]|[a-zA-Z\$&#037;])&charIden;*">
	<!ENTITY identifier       "&simpleIdentifier;(\.?&charIden;)*">
	<!ENTITY startIdentifier  "(\b[a-zA-Z]|\$[@#]|[\$&#037;])&charIden;*(\.?&charIden;)*">
	<!ENTITY mlsLevel         "&identifier;(\s*:\s*&identifier;(\s*,\s*&identifier;)*)?">
]>

<!--
  SELinux File Contexts Syntax Highlighting Definition for Kate
  ==========================================================================================
   This file is part of the KDE's KSyntaxHighlighting framework.

   Copyright (c) 2018-2019 Nibaldo González S. (nibgonz@gmail.com)

   Permission is hereby granted, free of charge, to any person obtaining a copy of this
   software and associated documentation files (the "Software"), to deal in the Software
   without restriction, including without limitation the rights to use, copy, modify, merge,
   publish, distribute, sublicense, and/or sell copies of the Software, and to permit
   persons to whom the Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
   PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
   COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
   AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  ==========================================================================================

  SELinux policy files with definitions of file contexts:
    - Labeling Policy Files: *.fc
    - Policy Config. Files: file_contexts, file_contexts_*, file_contexts.local,
        file_contexts.homedirs, file_contexts.template, homedir_template
    - SE for Android Policy Config. Files: service_contexts, property_contexts,
        hwservice_contexts
    - Policy Build Files: initial_sid_contexts, genfs_contexts, fs_use

  Change log:
   * Version 4 [02-Apr-2019]: Remove one indentation.
   * Version 3 [09-Sep-2018]:
      - Update itemData's style for the new Solarized color schemes.
   * Version 2 [28-Aug-2018]:
      - Some improvements. RegExp and some rules are moved to "selinux.xml".
      - Add statements keywords that use file contexts.
   * Version 1 [26-Jan-2018, by Nibaldo González]:
      - Initial version.
-->

<language name="SELinux File Contexts"
          version="4"
          kateversion="5.0"
          section="Other"
          extensions="*.fc;file_contexts;file_contexts_*;file_contexts.local;file_contexts.homedirs;file_contexts.template;homedir_template;property_contexts;service_contexts;hwservice_contexts;initial_sid_contexts;genfs_contexts;fs_use"
          priority="3"
          mimetype=""
          author="Nibaldo González (nibgonz@gmail.com)"
          license="MIT">

<highlighting>

	<contexts>

		<context name="_normal" attribute="Normal Text" lineEndContext="#stay">
			<IncludeRules context="_m4_preprocessor##SELinux Policy"/>
			<IncludeRules context="_find_comments##SELinux Policy"/>
			<RegExpr context="#stay" attribute="File Type" String="(\s|^)\-[bcdpls\-](?=\s|$)"/>

			<DetectChar context="_path_content" attribute="Path" char="/"/>
			<DetectChar context="_quoted" attribute="Text Quoted" char="&quot;"/>

			<!-- Content Quoted (M4).
			     NOTE: The default quotes (`text') are highlighted,
			     but another type of quotation mark can be used. -->
			<IncludeRules context="_m4_string_simple##SELinux Policy"/> <!-- `simple text' -->
			<IncludeRules context="_m4_quotes##SELinux Policy"/>

			<!-- File Contexts:  user:role:type:s0:c0 -->
			<RegExpr context="_fc_user" attribute="User" String="&startIdentifier;(?=(\s*:\s*&identifier;){2}(\s*:\s*&mlsLevel;(\s*\-\s*&mlsLevel;)?)?\b)"/>
			<WordDetect context="#stay" attribute="Other Keywords" String="&lt;&lt;none&gt;&gt;"/>

			<!-- Java-Language-Style Package Name & other Names, for SE Android (this avoid highlighting keywords) -->
			<RegExpr context="#stay" attribute="Path" String="\.?[a-zA-Z]\w*((\.|::)\w+)+(?=[^\(]|$)" firstNonSpace="true"/>

			<!-- Functions -->
			<DetectChar context="_parentheses_content" attribute="Normal Text" char="(" beginRegion="ParenthesesBlock"/>
			<IncludeRules context="_refpolicy_keywords_fc##SELinux Policy"/>
			<IncludeRules context="_m4_builtin_keywords##SELinux Policy"/>
			<RegExpr context="#stay" attribute="Function" String="\b[a-zA-Z][\w\-]*(?=\()"/>

			<IncludeRules context="_m4_special_arguments##SELinux Policy"/>
			<IncludeRules context="_common_special_char##SELinux Policy"/>
			<IncludeRules context="_line_continue_escape##SELinux Policy"/>

			<!-- Default Variables -->
			<StringDetect context="_path_content" attribute="Variable" String="HOME_DIR"/>
			<StringDetect context="_path_content" attribute="Variable" String="HOME_ROOT"/>

			<DetectChar context="_path_content" attribute="Path" char="[" lookAhead="true"/>
			<Detect2Chars context="_path_content" char="%" char1="{" lookAhead="true"/>
			<RegExpr context="_path_content" attribute="Path" String="\b[\w\[\]\.@\=\*\-\$%\+!\|&amp;\^~\{\}&lt;&gt;\?\\,]+[/\\\*\?\[\{]" lookAhead="true" firstNonSpace="true"/>

			<DetectChar context="#stay" attribute="Symbol" char="{" beginRegion="Bracket"/>
			<DetectChar context="#stay" attribute="Symbol" char="}" endRegion="Bracket"/>
			<AnyChar context="#stay" attribute="Symbol" String=",;~[]"/>

			<!-- Highlight only the statements that contain definition of file contexts -->
			<IncludeRules context="_statements_file_contexts##SELinux Policy"/>
			<RegExpr context="#stay" String="[a-zA-Z](\.?[\w\-]+)*"/>
			<HlCHex context="#pop" attribute="Number"/>
			<Int context="#pop" attribute="Number"/>
		</context>

		<context name="_parentheses_content" attribute="Normal Text" lineEndContext="#stay">
			<DetectChar context="#pop" attribute="Normal Text" char=")" endRegion="ParenthesesBlock"/>
			<!-- File Contexts:  (user:role:type,s0) -->
			<RegExpr context="_gen_context_fc_user" attribute="User" String="&startIdentifier;(\s*:\s*&identifier;){2}(\s*,\s*&identifier;)*\b" lookAhead="true"/>
			<IncludeRules context="_normal"/>
		</context>

		<context name="_path_content" attribute="Path" lineEndContext="#pop">
			<DetectSpaces context="#pop" lookAhead="true"/>
			<IncludeRules context="_regex##SELinux Policy"/>
			<IncludeRules context="_variable"/>
		</context>
		<context name="_quoted" attribute="Text Quoted" lineEndContext="#pop">
			<DetectChar context="#pop" attribute="Text Quoted" char="&quot;"/>
			<IncludeRules context="_m4_special_arguments##SELinux Policy"/>
			<IncludeRules context="_other_variable"/>
			<IncludeRules context="_regex_quoted##SELinux Policy"/>
			<RegExpr context="#stay" attribute="Text Quoted Open" String="[^\s&quot;\[\(\\](?=\s*$)"/>
		</context>

		<!-- Variables of "file_contexts", M4 & Refpolicy -->
		<context name="_variable" attribute="Normal Text" lineEndContext="#stay">
			<WordDetect context="#stay" attribute="Variable" String="HOME_DIR"/>
			<WordDetect context="#stay" attribute="Variable" String="HOME_ROOT"/>
			<StringDetect context="#stay" attribute="Variable" String="USER"/>
			<StringDetect context="#stay" attribute="Variable" String="ROLE"/>
			<IncludeRules context="_other_variable"/>
		</context>
		<context name="_other_variable" attribute="Normal Text" lineEndContext="#stay">
			<RegExpr context="#stay" attribute="Variable" String="\%\{[a-zA-Z]\w*\}"/>
		</context>
		<context name="_fc_variable" attribute="Path" lineEndContext="#pop">
			<IncludeRules context="_m4_special_arguments##SELinux Policy"/>
			<IncludeRules context="_other_variable"/>
		</context>

		<!-- SELinux Security Contexts -->

		<!-- User -->
		<context name="_fc_user" attribute="User" lineEndContext="#pop">
			<DetectChar context="#pop!_fc_role" attribute="Normal Text" char=":"/>
		</context>
		<!-- Role -->
		<context name="_fc_role" attribute="Role" lineEndContext="#pop">
			<DetectChar context="#pop!_fc_type" attribute="Normal Text" char=":"/>
		</context>
		<!-- Type Enforcement -->
		<context name="_fc_type" attribute="Type Enforcement" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop!_after_fc">
			<RegExpr context="#pop!_fc_mls" attribute="Type Enforcement" String="\s*&identifier;(?=\s*:\s*&mlsLevel;)"/> <!-- Find MLS/MCS -->
			<RegExpr context="#pop" attribute="Type Enforcement" String="\s*&identifier;"/>
		</context>

		<!-- Start MLS/MCS -->
		<context name="_fc_mls" attribute="MLS/MCS Level" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop!_after_fc">
			<DetectChar context="#pop!_fc_find_level_range" attribute="Normal Text" char=":"/>
			<DetectSpaces context="#stay" attribute="Normal Text"/>
		</context>
		<context name="_fc_find_level_range" attribute="MLS/MCS Level"
		         lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop!_fc_level_range">
			<DetectSpaces context="#stay" attribute="Normal Text"/>
		</context>
		<!-- MLS/MCS Range (Sensitivity:Category - Sensitivity:Category) -->
		<!-- Sensitivity -->
		<context name="_fc_level_range" attribute="MLS/MCS Level" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop!_after_fc">
			<RegExpr context="#pop!_fc_level_range_cat" attribute="Normal Text" String="\s*:\s*(?=&identifier;)"/> <!-- Find Category -->
			<RegExpr context="#pop!_fc_level" attribute="Normal Text" String="\s*\-\s*(?=&mlsLevel;)"/> <!-- Find Range -->
			<IncludeRules context="_default_level"/>
		</context>
		<!-- Category -->
		<context name="_fc_level_range_cat" attribute="MLS/MCS Level" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop!_after_fc">
			<RegExpr context="#pop!_fc_level" attribute="Normal Text" String="\s*\-\s*(?=&mlsLevel;)"/> <!-- Find Range -->
			<RegExpr context="#stay" attribute="Normal Text" String="\s*,\s*(?=&simpleIdentifier;)"/>
			<IncludeRules context="_default_level"/>
		</context>
		<!-- MLS/MCS Level (Sensitivity:Category) -->
		<!-- Sensitivity -->
		<context name="_fc_level" attribute="MLS/MCS Level" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop!_after_fc">
			<RegExpr context="#pop!_fc_level_cat" attribute="Normal Text" String="\s*:\s*(?=&identifier;)"/> <!-- Find Category -->
			<IncludeRules context="_default_level"/>
		</context>
		<!-- Category -->
		<context name="_fc_level_cat" attribute="MLS/MCS Level" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop!_after_fc">
			<RegExpr context="#stay" attribute="Normal Text" String="\s*,\s*(?=&simpleIdentifier;)"/>
			<IncludeRules context="_default_level"/>
		</context>

		<context name="_default_level" attribute="Normal Text" lineEndContext="#pop">
			<RegExpr context="#stay" attribute="Normal Text" String="\s*\.\s*(?=&charIden;)"/>
			<DetectChar  context="_default_level_arg" attribute="MLS/MCS Level" char="$"/>
			<DetectChar  context="_default_level_var" attribute="MLS/MCS Level" char="%"/>
			<RegExpr context="#stay" attribute="MLS/MCS Level" String="\w+"/>
			<DetectChar context="#stay" attribute="MLS/MCS Level" char="-"/>
		</context>
		<context name="_default_level_arg" attribute="MLS/MCS Level" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
			<!-- M4 Args. It is not exact -->
			<Int context="#pop" attribute="MLS/MCS Level"/>
			<AnyChar context="#pop" attribute="MLS/MCS Level" String="#*@"/>
			<RegExpr context="#pop" attribute="MLS/MCS Level" String="\{\d+\}"/>
		</context>
		<context name="_default_level_var" attribute="MLS/MCS Level" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
			<RegExpr context="#pop" attribute="MLS/MCS Level" String="{[A-Za-z]\w*\}"/>
		</context>

		<context name="_after_fc" attribute="Normal Text" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
			<RegExpr context="#stay" attribute="Normal Text" String="\s*:\s*\w*"/>
			<RegExpr context="#stay" attribute="Normal Text" String="[:\.\w]+"/>
		</context>

		<!-- Within function "gen_context" (highlight variables and M4 args.) -->
		<!-- User -->
		<context name="_gen_context_fc_user" attribute="User" lineEndContext="#pop">
			<DetectChar context="#pop!_gen_context_role" attribute="Normal Text" char=":"/>
			<IncludeRules context="_fc_variable"/>
		</context>
		<!-- Role -->
		<context name="_gen_context_role" attribute="Role" lineEndContext="#pop">
			<DetectChar context="#pop!_before_gen_context_type" attribute="Normal Text" char=":"/>
			<IncludeRules context="_fc_variable"/>
		</context>
		<!-- Type Enforcement -->
		<context name="_before_gen_context_type" attribute="Type Enforcement"
		         lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop!_gen_context_type">
			<DetectSpaces context="#stay" attribute="Normal Text"/>
		</context>
		<context name="_gen_context_type" attribute="Type Enforcement"
		         lineEndContext="#pop!_fc_find_comma" fallthrough="true" fallthroughContext="#pop!_fc_find_comma">
			<RegExpr context="#pop!_fc_level_range" attribute="Normal Text" String="\s*:\s*(?=&identifier;)"/> <!-- Find MLS/MCS -->
			<IncludeRules context="_fc_variable"/>
			<RegExpr context="#stay" attribute="Type Enforcement" String="[\w\-]+"/>
		</context>
		<!-- Comma after file contexts -->
		<context name="_fc_find_comma" attribute="Normal Text" lineEndContext="#stay" fallthrough="true" fallthroughContext="#pop">
			<DetectChar context="#pop!_fc_after_comma" attribute="Normal Text" char=","/>
			<RegExpr context="#pop" String="\s*[^,\s]" lookAhead="true"/>
			<DetectSpaces />
		</context>
		<context name="_fc_after_comma" attribute="Normal Text"
		         lineEndContext="#stay" fallthrough="true" fallthroughContext="#pop!_gen_context_level">
			<DetectSpaces context="#stay"/>
		</context>
		<!-- MLS/MCS -->
		<context name="_gen_context_level" attribute="MLS/MCS Level" lineEndContext="#stay" fallthrough="true" fallthroughContext="#pop">
			<RegExpr context="#stay" attribute="Normal Text" String="\-\s*(?=&simpleIdentifier;)"/>
			<IncludeRules context="_fc_variable"/>
			<RegExpr context="#stay" attribute="MLS/MCS Level" String="\w+"/>
			<DetectChar context="#stay" attribute="MLS/MCS Level" char="-"/>
			<AnyChar context="#stay" attribute="Normal Text" String=":.,"/>
			<DetectSpaces />
		</context>

	</contexts>

	<itemDatas>
		<itemData name="Normal Text" defStyleNum="dsNormal"   spellChecking="false"/>
		<itemData name="Text Quoted" defStyleNum="dsString"   spellChecking="false"/>
		<itemData name="Path"        defStyleNum="dsNormal"   spellChecking="false"/>
		<itemData name="Variable"    defStyleNum="dsVariable" spellChecking="false"/>
		<itemData name="File Type"   defStyleNum="dsKeyword"  spellChecking="false"/>

		<itemData name="User"             defStyleNum="dsPreprocessor"   spellChecking="false"/>
		<itemData name="Role"             defStyleNum="dsInformation"    spellChecking="false"/>
		<itemData name="Type Enforcement" defStyleNum="dsAttribute"      spellChecking="false"/>
		<itemData name="MLS/MCS Level"    defStyleNum="dsVerbatimString" spellChecking="false"/>

		<itemData name="Other Keywords"   defStyleNum="dsNormal"   italic="1" spellChecking="false"/>
		<itemData name="Function"         defStyleNum="dsNormal"   bold="1" spellChecking="false"/>
		<itemData name="Symbol"           defStyleNum="dsOperator" spellChecking="false"/>
		<itemData name="Number"           defStyleNum="dsComment"  italic="0" underline="0" spellChecking="false"/>
		<itemData name="Text Quoted Open" defStyleNum="dsString"   underline="1" spellChecking="false"/>
	</itemDatas>

</highlighting>

<general>
	<keywords casesensitive="true" additionalDeliminator="&quot;&apos;&#096;" weakDeliminator="*?+.-"/>
	<comments>
		<comment name="singleLine" start="#"/>
	</comments>
</general>

</language>
<!-- kate: replace-tabs off; tab-width 3; indent-width 3; remove-trailing-spaces mod; dynamic-word-wrap off; -->
