summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-09-27 17:25:36 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-09-27 17:25:36 -0600
commite5e15c04bc58c34906e6d7cfcbad68d1a5617563 (patch)
tree580f5fb0fafc7e974c969fc8aae229205c836195
parent71e1a86a033c380f85dd300d788af63bfef25bab (diff)
wip
-rw-r--r--.gitignore6
-rw-r--r--3rd-party/.gitignore1
-rw-r--r--3rd-party/MS-LCID.txt4073
-rw-r--r--CMakeLists.txt32
-rw-r--r--HACKING.md10
-rw-r--r--PLAN.md2
-rw-r--r--cmd/sbc_harness/CMakeLists.txt23
-rw-r--r--cmd/sbc_harness/config/config.h (renamed from config.h)6
-rw-r--r--cmd/sbc_harness/config/tusb_config.h (renamed from libusb/tusb_config.h)0
-rw-r--r--cmd/sbc_harness/main.c (renamed from cmd/harness/main.c)0
-rw-r--r--cmd/sbc_harness/usb_keyboard.c (renamed from cmd/harness/usb_keyboard.c)0
-rw-r--r--cmd/sbc_harness/usb_keyboard.h (renamed from cmd/harness/usb_keyboard.h)0
-rw-r--r--cmd/srv9p/CMakeLists.txt15
l---------cmd/srv9p/config/config.h1
-rw-r--r--lib9p/.editorconfig2
-rw-r--r--lib9p/.gitignore2
-rw-r--r--lib9p/9P2000.e.txt4
-rw-r--r--lib9p/9P2000.u.txt25
-rw-r--r--lib9p/9p.c (renamed from lib9p/defs.c)39
-rw-r--r--lib9p/9p.h15
-rw-r--r--lib9p/CMakeLists.txt34
-rwxr-xr-xlib9p/defs.gen456
-rw-r--r--lib9p/defs.h74
-rw-r--r--lib9p/include/lib9p/9p.h72
-rw-r--r--lib9p/include/lib9p/_types.h285
-rwxr-xr-xlib9p/include/lib9p/linux-errno.h.gen (renamed from lib9p/linux-errno.h.gen)0
-rw-r--r--lib9p/include/lib9p/srv.h16
-rw-r--r--lib9p/internal.h79
-rw-r--r--lib9p/misc.txt24
-rw-r--r--lib9p/srv.h16
-rw-r--r--lib9p/types.c1331
-rwxr-xr-xlib9p/types.gen611
-rw-r--r--libcr/CMakeLists.txt10
-rw-r--r--libcr/coroutine.c2
-rw-r--r--libcr/include/libcr/coroutine.h (renamed from libcr/coroutine.h)2
-rw-r--r--libcr_ipc/CMakeLists.txt10
-rw-r--r--libcr_ipc/include/libcr_ipc/chan.h (renamed from libcr_ipc/coroutine_chan.h)0
-rw-r--r--libcr_ipc/include/libcr_ipc/rpc.h (renamed from libcr_ipc/coroutine_rpc.h)0
-rw-r--r--libcr_ipc/include/libcr_ipc/sema.h (renamed from libcr_ipc/coroutine_sema.h)0
-rw-r--r--libcr_ipc/sema.c (renamed from libcr_ipc/coroutine_sema.c)0
-rw-r--r--libnetio/CMakeLists.txt10
-rw-r--r--libusb/CMakeLists.txt23
-rw-r--r--libusb/include/libusb/tusb_helpers.h (renamed from libusb/tusb_helpers.h)0
-rwxr-xr-xlibusb/include/libusb/tusb_helpers.h.gen (renamed from libusb/tusb_helpers.h.gen)20
-rw-r--r--libusb/include/libusb/usb_common.h (renamed from libusb/usb_common.h)0
45 files changed, 6655 insertions, 676 deletions
diff --git a/.gitignore b/.gitignore
index fa00101..9e280fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,8 +2,4 @@
*.log
.mypy_cache/
-/build/
-
-/tusb_helpers.h
-
-/srv9p
+build/
diff --git a/3rd-party/.gitignore b/3rd-party/.gitignore
deleted file mode 100644
index 4305236..0000000
--- a/3rd-party/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/MS-LCID.txt
diff --git a/3rd-party/MS-LCID.txt b/3rd-party/MS-LCID.txt
new file mode 100644
index 0000000..6bc95b1
--- /dev/null
+++ b/3rd-party/MS-LCID.txt
@@ -0,0 +1,4073 @@
+[MS-LCID]:
+Windows Language Code Identifier (LCID) Reference
+
+
+Intellectual Property Rights Notice for Open Specifications Documentation
+ Technical Documentation. Microsoft publishes Open Specifications documentation (“this
+ documentation”) for protocols, file formats, data portability, computer languages, and standards
+ support. Additionally, overview documents cover inter-protocol relationships and interactions.
+ Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other
+ terms that are contained in the terms of use for the Microsoft website that hosts this
+ documentation, you can make copies of it in order to develop implementations of the technologies
+ that are described in this documentation and can distribute portions of it in your implementations
+ that use these technologies or in your documentation as necessary to properly document the
+ implementation. You can also distribute in your implementation, with or without modification, any
+ schemas, IDLs, or code samples that are included in the documentation. This permission also
+ applies to any documents that are referenced in the Open Specifications documentation.
+ No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation.
+ Patents. Microsoft has patents that might cover your implementations of the technologies
+ described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of
+ this documentation grants any licenses under those patents or any other Microsoft patents.
+ However, a given Open Specifications document might be covered by the Microsoft Open
+ Specifications Promise or the Microsoft Community Promise. If you would prefer a written license,
+ or if the technologies described in this documentation are not covered by the Open Specifications
+ Promise or Community Promise, as applicable, patent licenses are available by contacting
+ iplg@microsoft.com.
+ License Programs. To see all of the protocols in scope under a specific license program and the
+ associated patents, visit the Patent Map.
+ Trademarks. The names of companies and products contained in this documentation might be
+ covered by trademarks or similar intellectual property rights. This notice does not grant any
+ licenses under those rights. For a list of Microsoft trademarks, visit
+ www.microsoft.com/trademarks.
+ Fictitious Names. The example companies, organizations, products, domain names, email
+ addresses, logos, people, places, and events that are depicted in this documentation are fictitious.
+ No association with any real company, organization, product, domain name, email address, logo,
+ person, place, or event is intended or should be inferred.
+Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other
+than as specifically described above, whether by implication, estoppel, or otherwise.
+
+Tools. The Open Specifications documentation does not require the use of Microsoft programming
+tools or programming environments in order for you to develop an implementation. If you have access
+to Microsoft programming tools and environments, you are free to take advantage of them. Certain
+Open Specifications documents are intended for use in conjunction with publicly available standards
+specifications and network programming art and, as such, assume that the reader either is familiar
+with the aforementioned material or has immediate access to it.
+
+Support. For questions and support, please contact dochelp@microsoft.com.
+
+
+
+
+ 1 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Revision Summary
+
+ Revision Revision
+ Date History Class Comments
+
+ 2/14/2008 2.1.3 Editorial Changed language and formatting in the technical content.
+
+ 3/14/2008 2.1.4 Editorial Changed language and formatting in the technical content.
+
+ 6/20/2008 2.1.5 Editorial Changed language and formatting in the technical content.
+
+ 7/25/2008 2.1.6 Editorial Changed language and formatting in the technical content.
+
+ 8/29/2008 2.2 Minor Clarified the meaning of the technical content.
+
+ 10/24/2008 2.2.1 Editorial Changed language and formatting in the technical content.
+
+ 12/5/2008 2.3 Minor Clarified the meaning of the technical content.
+
+ 1/16/2009 2.3.1 Editorial Changed language and formatting in the technical content.
+
+ 2/27/2009 2.3.2 Editorial Changed language and formatting in the technical content.
+
+ 4/10/2009 2.4 Minor Clarified the meaning of the technical content.
+
+ 5/22/2009 2.4.1 Editorial Changed language and formatting in the technical content.
+
+ 7/2/2009 2.4.2 Editorial Changed language and formatting in the technical content.
+
+ 8/14/2009 2.4.3 Editorial Changed language and formatting in the technical content.
+
+ 9/25/2009 3.0 Major Updated and revised the technical content.
+
+ 11/6/2009 3.0.1 Editorial Changed language and formatting in the technical content.
+
+ 12/18/2009 3.0.2 Editorial Changed language and formatting in the technical content.
+
+ 1/29/2010 3.1 Minor Clarified the meaning of the technical content.
+
+ 3/12/2010 3.1.1 Editorial Changed language and formatting in the technical content.
+
+ 4/23/2010 3.1.2 Editorial Changed language and formatting in the technical content.
+
+ 6/4/2010 3.1.3 Editorial Changed language and formatting in the technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 7/16/2010 3.1.3 None
+ technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 8/27/2010 3.1.3 None
+ technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 10/8/2010 3.1.3 None
+ technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 11/19/2010 3.1.3 None
+ technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 1/7/2011 3.1.3 None
+ technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 2/11/2011 3.1.3 None
+ technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 3/25/2011 3.1.3 None
+ technical content.
+
+
+ 2 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Revision Revision
+ Date History Class Comments
+
+ No changes to the meaning, language, or formatting of the
+ 5/6/2011 3.1.3 None
+ technical content.
+
+ 6/17/2011 3.2 Minor Clarified the meaning of the technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 9/23/2011 3.2 None
+ technical content.
+
+ 12/16/2011 4.0 Major Updated and revised the technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 3/30/2012 4.0 None
+ technical content.
+
+ 7/12/2012 5.0 Major Updated and revised the technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 10/25/2012 5.0 None
+ technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 1/31/2013 5.0 None
+ technical content.
+
+ 8/8/2013 6.0 Major Updated and revised the technical content.
+
+ 11/14/2013 6.1 Minor Clarified the meaning of the technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 2/13/2014 6.1 None
+ technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 5/15/2014 6.1 None
+ technical content.
+
+ 6/30/2015 7.0 Major Significantly changed the technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 10/16/2015 7.0 None
+ technical content.
+
+ 7/14/2016 8.0 Major Significantly changed the technical content.
+
+ 3/16/2017 9.0 Major Significantly changed the technical content.
+
+ No changes to the meaning, language, or formatting of the
+ 6/1/2017 9.0 None
+ technical content.
+
+ 9/15/2017 10.0 Major Significantly changed the technical content.
+
+ 12/1/2017 11.0 Major Significantly changed the technical content.
+
+ 9/12/2018 12.0 Major Significantly changed the technical content.
+
+ 3/13/2019 13.0 Major Significantly changed the technical content.
+
+ 3/4/2020 14.0 Major Significantly changed the technical content.
+
+ 4/7/2021 14.1 Minor Clarified the meaning of the technical content.
+
+ 6/25/2021 15.0 Major Significantly changed the technical content.
+
+ 4/23/2024 16.0 Major Significantly changed the technical content.
+
+
+
+
+ 3 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Table of Contents
+ 1 Introduction ............................................................................................................ 5
+ 1.1 Glossary ........................................................................................................... 5
+ 1.2 References ........................................................................................................ 6
+ 1.2.1 Normative References ................................................................................... 6
+ 1.2.2 Informative References ................................................................................. 6
+ 1.3 Overview .......................................................................................................... 6
+ 1.4 Relationship to Protocols and Other Structures ...................................................... 7
+ 1.5 Applicability Statement ....................................................................................... 7
+ 1.6 Versioning and Localization ................................................................................. 7
+ 1.7 Vendor-Extensible Fields ..................................................................................... 7
+ 2 Structures ............................................................................................................... 8
+ 2.1 Language Code Identifiers ................................................................................... 8
+ 2.2 LCID Structure ................................................................................................... 8
+ 2.2.1 Locale Names without LCIDs ........................................................................ 25
+ 3 Structure Examples ............................................................................................... 27
+ 4 Security Considerations ......................................................................................... 28
+ 5 Appendix A: Product Behavior ............................................................................... 29
+ 6 Change Tracking .................................................................................................... 60
+ 7 Index ..................................................................................................................... 61
+
+
+
+
+ 4 / 61
+ [MS-LCID] - v20240423
+ Windows Language Code Identifier (LCID) Reference
+ Copyright © 2024 Microsoft Corporation
+ Release: April 23, 2024
+ 1 Introduction
+This document provides an overview of language code identifiers (LCIDs), also known as culture
+identifiers, which are being deprecated, and the preferred alternate system of locale codes, which
+specify a set of locale identifiers that designate culture-specific information such as how text is sorted,
+how a date is formatted, and the display format for numbers and currency.
+
+Sections 1.7 and 2 of this specification are normative. All other sections and examples in this
+specification are informative.
+
+
+1.1 Glossary
+
+This document uses the following terms:
+
+ alternate sort: Specifies an alternate collation for a language that has multiple methods for
+ sorting data. For example, German has both "Dictionary" and "Phone Book" sorts. "Dictionary"
+ sorting (de-DE) is the default for German, but developers can specify the alternate "Phone
+ Book" sort (de-DE_phoneb) explicitly.
+
+ Chinese BIG5 order: Ideographs are ordered according to the code point values of the Taiwanese
+ BIG5 industrial standard.
+
+ Chinese radical/stroke order: Ideographs are ordered according to radical stroke count.
+
+ Chinese Unicode order: Deprecated. Identical to the default sort information used for English.
+
+ Georgian modern order: An order for the Georgian language that places archaic characters that
+ are no longer used at the end of the alphabet.
+
+ Georgian traditional order: An order for the Georgian language that intersperses archaic
+ characters that are no longer used among the rest of the alphabet in their traditional places.
+
+ German phone book order: An order that equates Ä, Ö, and Ü with AE, OE, and UE, respectively
+ (commonly used in German phone books).
+
+ Hungarian default order: The typical expected alphabetical order for the Hungarian language.
+
+ Hungarian technical order: A sort order that places capital letters before lowercase ones, unlike
+ most sorts, which sort lowercase first.
+
+ Japanese radical/stroke sort order: Ideographs are ordered by their radical and stroke
+ components, much like an ideographic dictionary might do.
+
+ Japanese Unicode order: Deprecated. Identical to the default sort information used for English,
+ except that the backslash (\) is equal to the currency symbol, 0x00A5, the yen sign.
+
+ Japanese XJIS order: Ideographs are ordered according to the code point values of the [JIS X
+ 208] and [JIS X 212] government standards.
+
+ Korean KSC order: Ideographs are ordered according to the Korean Hangul pronunciation, as
+ specified in the Korean [KSC5601] government standard.
+
+ Korean Unicode order: Deprecated. Identical to the default sort information used for English,
+ except that the backslash (\) is equal to the currency symbol, 0x20A9, the won sign.
+
+ neutral locale: A locale describing a language without any region-specific information.
+
+ PRC Chinese phonetic order: Ideographs are ordered according to their A to Z pronunciation
+ order.
+
+
+ 5 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ PRC Chinese stroke count order: Ideographs are ordered according to their stroke count.
+
+ specific locale: A locale describing a language that has a qualifying regional variant. For example,
+ variants for English can be en-US or en-GB.
+
+ Traditional Chinese Bopomofo order: Ideographs are ordered by their most common Mandarin
+ pronunciation, using the Chinese Bopomofo order of the pronunciations.
+
+ MAY, SHOULD, MUST, SHOULD NOT, MUST NOT: These terms (in all caps) are used as defined
+ in [RFC2119]. All statements of optional behavior use either MAY, SHOULD, or SHOULD NOT.
+
+
+1.2 References
+
+Links to a document in the Microsoft Open Specifications library point to the correct section in the
+most recently published version of the referenced document. However, because individual documents
+in the library are not updated at the same time, the section numbers in the documents may not
+match. You can confirm the correct section numbering by checking the Errata.
+
+
+1.2.1 Normative References
+
+We conduct frequent surveys of the normative references to assure their continued availability. If you
+have any issue with finding a normative reference, please contact dochelp@microsoft.com. We will
+assist you in finding the relevant information.
+
+[ISO-15924] International Organization for Standardization, "ISO 15924 Registration Authority",
+http://www.unicode.org/iso15924/
+
+[ISO-3166] International Organization for Standardization, "Codes for the representation of names of
+countries and their subdivisions -- Part1: Country codes", ISO 3166-1:2013, November 2013,
+http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=63545
+
+Note There is a charge to download the specification.
+
+[ISO-639] International Organization for Standardization, "Codes for the representation of names of
+languages -- Part 2: Alpha-3 code", ISO 639-2:1998,
+http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=4767
+
+Note There is a charge to download this specification.
+
+[MS-DTYP] Microsoft Corporation, "Windows Data Types".
+
+[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC
+2119, March 1997, https://www.rfc-editor.org/info/rfc2119
+
+[RFC5646] Phillips, A, and Davis, M., "Tags for Identifying Languages", BCP 47, RFC 4646, September
+2006, https://www.rfc-editor.org/info/rfc5646
+
+
+1.2.2 Informative References
+
+[KSC5601] Korea Industrial Standards Association, "Code for Information Interchange (Hangul and
+Hanja)", Korean Industrial Standard, 1987, Ref. No. KS C 5601-1987.
+
+
+1.3 Overview
+
+The LCID structure is used to identify specific languages for the purpose of customizing software for
+particular languages and cultures. For example, it can specify the way dates, times, and numbers are
+formatted as strings. It can also specify paper sizes and preferred sort order based on language
+elements.
+
+ 6 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ LCIDs are being deprecated, and implementers are strongly encouraged to use locale names instead.
+LCIDs can be used for backward compatibility, but as noted in section 2.2.1, there is no guarantee of
+LCID uniqueness when used with valid locale names not otherwise associated with an LCID.
+
+
+1.4 Relationship to Protocols and Other Structures
+
+This structure is related to protocols and structures that need to make special cases for specific
+languages and cultures.
+
+
+1.5 Applicability Statement
+
+This structure applies in scenarios where special cases need to be made for specific languages and
+cultures.
+
+
+1.6 Versioning and Localization
+
+This structure serves to identify particular languages, locales, and cultures.
+
+
+1.7 Vendor-Extensible Fields
+
+None.
+
+
+
+
+ 7 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ 2 Structures
+
+2.1 Language Code Identifiers
+
+LCIDs are identifiers used to specify localizable information. They are also known as culture identifiers
+in the Microsoft .NET Framework environment.
+
+The name of a culture consists of its [ISO-639] language code, its [ISO-3166] country/region code,
+and an optional [ISO-15924] script tag for the written language. For example, the name of the culture
+in which the language is Bosnian (as written in Latin script and used in the Bosnia and Herzegovina
+region) is bs-Latn-BA.<1><2><3>
+
+
+2.2 LCID Structure
+
+This protocol references commonly used data types as defined in [MS-DTYP].
+
+An LCID is a 4-byte value. The value supplied in an LCID is a standard numeric substitution for the
+international [RFC5646] string.
+
+The following diagram is shown in host byte order.
+
+ 1 2 3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+
+ Reserved Sort ID Language ID
+
+
+Reserved (12 bits): This field is reserved for future use. It MUST be 0.
+
+Sort ID (4 bits): The sort order. In most cases, this value can be 0x0, which indicates a default sort
+ (SORT_DEFAULT). However, other values can be used when an alternate sort is required. These
+ alternate values are listed in the following table. For example, 0x0407 (German - Germany)
+ becomes 0x10407 when SORT_GERMAN_PHONE_BOOK is used.
+
+ Value Meaning
+
+ SORT_CHINESE_BIG5 Chinese BIG5 order
+ 0x0 Default sort for Simplified Chinese locales
+ Use with zh-TW, zh-HK, or zh-MO
+
+ SORT_CHINESE_PRCP PRC Chinese phonetic order
+ 0x0 Default sort for Traditional Chinese locales.
+ Use with zn-CN or zh-SG
+
+ SORT_DEFAULT Default sort order
+ 0x0
+
+ SORT_GEORGIAN_TRADITIONAL Georgian traditional order
+ 0x0 Default sort for Georgian, use with ka-GE
+
+ SORT_HUNGARIAN_DEFAULT Hungarian default order
+ 0x0 Default sort for Hungarian, use with hu-HU
+
+ SORT_JAPANESE_XJIS Japanese XJIS order
+ 0x0 Use with ja-JP
+
+ SORT_KOREAN_KSC Korean KSC order
+
+
+ 8 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Value Meaning
+
+ 0x0 Default sort for Korean, use with ko-KR
+
+ SORT_CHINESE_UNICODE Chinese Unicode order<4>
+ 0x1 Do not use, deprecated
+
+ SORT_GEORGIAN_MODERN Georgian modern order
+ 0x1 Use with ka-GE, resolves to ka-GE_modern
+
+ SORT_GERMAN_PHONE_BOOK German phone book order
+ 0x1 Use with de-DE, resolves to de-DE_phoneb
+
+ SORT_HUNGARIAN_TECHNICAL Hungarian technical order
+ 0x1 Use with hu-HU, resolves to hu-HU_technl
+
+ SORT_JAPANESE_UNICODE Japanese Unicode order<5>
+ 0x1 Do not use, deprecated
+
+ SORT_KOREAN_UNICODE Korean Unicode order<6>
+ 0x1 Do not use, deprecated
+
+ SORT_CHINESE_PRC PRC Chinese stroke count order
+ 0x2 Use with zh-CN, resolves to zh-CN_stroke
+ Use with zh-SG, resolves to zh-SG_stroke
+
+ SORT_CHINESE_BOPOMOFO Traditional Chinese Bopomofo order
+ 0x3 Use with zh-TW, resolves to zh-TW_pronun
+
+ SORT_CHINESE_RADICALSTROKE Chinese radical/stroke order<7>
+ 0x4 Use with zh-HK, resolves to zh-HK_radstr
+ Use with zh-MO, resolves to zh-MO_radstr
+ Use with zh-TW, resolves to zh-TW_radstr
+
+ SORT_JAPANESE_RADICALSTROKE Japanese radical/stroke sort order
+ 0x4 Use with ja-JP, resolves to ja-JP_radstr
+
+
+Language ID (2 bytes): The language component of the LCID.<8>
+
+ Language ID Language tag
+
+ 0x0001 ar
+
+ 0x0002 bg
+
+ 0x0003 ca
+
+ 0x0004 zh-Hans
+
+ 0x0005 cs
+
+ 0x0006 da
+
+ 0x0007 de
+
+ 0x0008 el
+
+ 0x0009 en
+
+ 0x000A es
+
+
+ 9 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x000B fi
+
+ 0x000C fr
+
+ 0x000D he
+
+ 0x000E hu
+
+ 0x000F is
+
+ 0x0010 it
+
+ 0x0011 ja
+
+ 0x0012 ko
+
+ 0x0013 nl
+
+ 0x0014 no
+
+ 0x0015 pl
+
+ 0x0016 pt
+
+ 0x0017 rm
+
+ 0x0018 ro
+
+ 0x0019 ru
+
+ 0x001A hr
+
+ 0x001B sk
+
+ 0x001C sq
+
+ 0x001D sv
+
+ 0x001E th
+
+ 0x001F tr
+
+ 0x0020 ur
+
+ 0x0021 id
+
+ 0x0022 uk
+
+ 0x0023 be
+
+ 0x0024 sl
+
+ 0x0025 et
+
+ 0x0026 lv
+
+ 0x0027 lt
+
+ 0x0028 tg
+
+ 0x0029 fa
+
+ 0x002A vi
+
+
+ 10 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x002B hy
+
+ 0x002C az
+
+ 0x002D eu
+
+ 0x002E hsb
+
+ 0x002F mk
+
+ 0x0030 st
+
+ 0x0031 ts
+
+ 0x0032 tn
+
+ 0x0033 ve
+
+ 0x0034 xh
+
+ 0x0035 zu
+
+ 0x0036 af
+
+ 0x0037 ka
+
+ 0x0038 fo
+
+ 0x0039 hi
+
+ 0x003A mt
+
+ 0x003B se
+
+ 0x003C ga
+
+ 0x003D yi, reserved
+
+ 0x003E ms
+
+ 0x003F kk
+
+ 0x0040 ky
+
+ 0x0041 sw
+
+ 0x0042 tk
+
+ 0x0043 uz
+
+ 0x0044 tt
+
+ 0x0045 bn
+
+ 0x0046 pa
+
+ 0x0047 gu
+
+ 0x0048 or
+
+ 0x0049 ta
+
+ 0x004A te
+
+
+ 11 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x004B kn
+
+ 0x004C ml
+
+ 0x004D as
+
+ 0x004E mr
+
+ 0x004F sa
+
+ 0x0050 mn
+
+ 0x0051 bo
+
+ 0x0052 cy
+
+ 0x0053 km
+
+ 0x0054 lo
+
+ 0x0055 my
+
+ 0x0056 gl
+
+ 0x0057 kok
+
+ 0x0058 mni, reserved
+
+ 0x0059 sd
+
+ 0x005A syr
+
+ 0x005B si
+
+ 0x005C chr
+
+ 0x005D iu
+
+ 0x005E am
+
+ 0x005F tzm
+
+ 0x0060 ks
+
+ 0x0061 ne
+
+ 0x0062 fy
+
+ 0x0063 ps
+
+ 0x0064 fil
+
+ 0x0065 dv
+
+ 0x0066 bin, reserved
+
+ 0x0067 ff
+
+ 0x0068 ha
+
+ 0x0069 ibb, reserved
+
+ 0x006A yo
+
+
+ 12 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x006B quz
+
+ 0x006C nso
+
+ 0x006D ba
+
+ 0x006E lb
+
+ 0x006F kl
+
+ 0x0070 ig
+
+ 0x0071 kr, reserved
+
+ 0x0072 om
+
+ 0x0073 ti
+
+ 0x0074 gn
+
+ 0x0075 haw
+
+ 0x0076 la, reserved
+
+ 0x0077 so, reserved
+
+ 0x0078 ii
+
+ 0x0079 pap, reserved
+
+ 0x007A arn
+
+ 0x007B Neither defined nor reserved
+
+ 0x007C moh
+
+ 0x007D Neither defined nor reserved
+
+ 0x007E br
+
+ 0x007F Reserved for invariant locale behavior
+
+ 0x0080 ug
+
+ 0x0081 mi
+
+ 0x0082 oc
+
+ 0x0083 co
+
+ 0x0084 gsw
+
+ 0x0085 sah
+
+ 0x0086 qut
+
+ 0x0087 rw
+
+ 0x0088 wo
+
+ 0x0089 Neither defined nor reserved
+
+ 0x008A Neither defined nor reserved
+
+
+ 13 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x008B Neither defined nor reserved
+
+ 0x008C prs
+
+ 0x008D Neither defined nor reserved
+
+ 0x008E Neither defined nor reserved
+
+ 0x008F Neither defined nor reserved
+
+ 0x0090 Neither defined nor reserved
+
+ 0x0091 gd
+
+ 0x0092 ku
+
+ 0x0093 quc, reserved
+
+ 0x0401 ar-SA
+
+ 0x0402 bg-BG
+
+ 0x0403 ca-ES
+
+ 0x0404 zh-TW
+
+ 0x0405 cs-CZ
+
+ 0x0406 da-DK
+
+ 0x0407 de-DE
+
+ 0x0408 el-GR
+
+ 0x0409 en-US
+
+ 0x040A es-ES_tradnl
+
+ 0x040B fi-FI
+
+ 0x040C fr-FR
+
+ 0x040D he-IL
+
+ 0x040E hu-HU
+
+ 0x040F is-IS
+
+ 0x0410 it-IT
+
+ 0x0411 ja-JP
+
+ 0x0412 ko-KR
+
+ 0x0413 nl-NL
+
+ 0x0414 nb-NO
+
+ 0x0415 pl-PL
+
+ 0x0416 pt-BR
+
+ 0x0417 rm-CH
+
+
+ 14 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x0418 ro-RO
+
+ 0x0419 ru-RU
+
+ 0x041A hr-HR
+
+ 0x041B sk-SK
+
+ 0x041C sq-AL
+
+ 0x041D sv-SE
+
+ 0x041E th-TH
+
+ 0x041F tr-TR
+
+ 0x0420 ur-PK
+
+ 0x0421 id-ID
+
+ 0x0422 uk-UA
+
+ 0x0423 be-BY
+
+ 0x0424 sl-SI
+
+ 0x0425 et-EE
+
+ 0x0426 lv-LV
+
+ 0x0427 lt-LT
+
+ 0x0428 tg-Cyrl-TJ
+
+ 0x0429 fa-IR
+
+ 0x042A vi-VN
+
+ 0x042B hy-AM
+
+ 0x042C az-Latn-AZ
+
+ 0x042D eu-ES
+
+ 0x042E hsb-DE
+
+ 0x042F mk-MK
+
+ 0x0430 st-ZA
+
+ 0x0431 ts-ZA
+
+ 0x0432 tn-ZA
+
+ 0x0433 ve-ZA
+
+ 0x0434 xh-ZA
+
+ 0x0435 zu-ZA
+
+ 0x0436 af-ZA
+
+ 0x0437 ka-GE
+
+
+ 15 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x0438 fo-FO
+
+ 0x0439 hi-IN
+
+ 0x043A mt-MT
+
+ 0x043B se-NO
+
+ 0x043D yi-001
+
+ 0x043E ms-MY
+
+ 0x043F kk-KZ
+
+ 0x0440 ky-KG
+
+ 0x0441 sw-KE
+
+ 0x0442 tk-TM
+
+ 0x0443 uz-Latn-UZ
+
+ 0x0444 tt-RU
+
+ 0x0445 bn-IN
+
+ 0x0446 pa-IN
+
+ 0x0447 gu-IN
+
+ 0x0448 or-IN
+
+ 0x0449 ta-IN
+
+ 0x044A te-IN
+
+ 0x044B kn-IN
+
+ 0x044C ml-IN
+
+ 0x044D as-IN
+
+ 0x044E mr-IN
+
+ 0x044F sa-IN
+
+ 0x0450 mn-MN
+
+ 0x0451 bo-CN
+
+ 0x0452 cy-GB
+
+ 0x0453 km-KH
+
+ 0x0454 lo-LA
+
+ 0x0455 my-MM
+
+ 0x0456 gl-ES
+
+ 0x0457 kok-IN
+
+ 0x0458 mni-IN, reserved
+
+
+ 16 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x0459 sd-Deva-IN, reserved
+
+ 0x045A syr-SY
+
+ 0x045B si-LK
+
+ 0x045C chr-Cher-US
+
+ 0x045D iu-Cans-CA
+
+ 0x045E am-ET
+
+ 0x045F tzm-Arab-MA
+
+ 0x0460 ks-Arab
+
+ 0x0461 ne-NP
+
+ 0x0462 fy-NL
+
+ 0x0463 ps-AF
+
+ 0x0464 fil-PH
+
+ 0x0465 dv-MV
+
+ 0x0466 bin-NG, reserved
+
+ 0x0467 ff-NG, ff-Latn-NG
+
+ 0x0468 ha-Latn-NG
+
+ 0x0469 ibb-NG, reserved
+
+ 0x046A yo-NG
+
+ 0x046B quz-BO
+
+ 0x046C nso-ZA
+
+ 0x046D ba-RU
+
+ 0x046E lb-LU
+
+ 0x046F kl-GL
+
+ 0x0470 ig-NG
+
+ 0x0471 kr-Latn-NG
+
+ 0x0472 om-ET
+
+ 0x0473 ti-ET
+
+ 0x0474 gn-PY
+
+ 0x0475 haw-US
+
+ 0x0476 la-VA
+
+ 0x0477 so-SO
+
+ 0x0478 ii-CN
+
+
+ 17 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x0479 pap-029, reserved
+
+ 0x047A arn-CL
+
+ 0x047C moh-CA
+
+ 0x047E br-FR
+
+ 0x0480 ug-CN
+
+ 0x0481 mi-NZ
+
+ 0x0482 oc-FR
+
+ 0x0483 co-FR
+
+ 0x0484 gsw-FR
+
+ 0x0485 sah-RU
+
+ 0x0486 qut-GT, reserved
+
+ 0x0487 rw-RW
+
+ 0x0488 wo-SN
+
+ 0x048C prs-AF
+
+ 0x048D plt-MG, reserved
+
+ 0x048E zh-yue-HK, reserved
+
+ 0x048F tdd-Tale-CN, reserved
+
+ 0x0490 khb-Talu-CN, reserved
+
+ 0x0491 gd-GB
+
+ 0x0492 ku-Arab-IQ
+
+ 0x0493 quc-CO, reserved
+
+ 0x0501 qps-ploc
+
+ 0x05FE qps-ploca
+
+ 0x0801 ar-IQ
+
+ 0x0803 ca-ES-valencia
+
+ 0x0804 zh-CN
+
+ 0x0807 de-CH
+
+ 0x0809 en-GB
+
+ 0x080A es-MX
+
+ 0x080C fr-BE
+
+ 0x0810 it-CH
+
+ 0x0811 ja-Ploc-JP, reserved
+
+
+ 18 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x0813 nl-BE
+
+ 0x0814 nn-NO
+
+ 0x0816 pt-PT
+
+ 0x0818 ro-MD
+
+ 0x0819 ru-MD
+
+ 0x081A sr-Latn-CS
+
+ 0x081D sv-FI
+
+ 0x0820 ur-IN
+
+ 0x0827 Neither defined nor reserved
+
+ 0x082C az-Cyrl-AZ, reserved
+
+ 0x082E dsb-DE
+
+ 0x0832 tn-BW
+
+ 0x083B se-SE
+
+ 0x083C ga-IE
+
+ 0x083E ms-BN
+
+ 0x083F kk-Latn-KZ, reserved
+
+ 0x0843 uz-Cyrl-UZ, reserved
+
+ 0x0845 bn-BD
+
+ 0x0846 pa-Arab-PK
+
+ 0x0849 ta-LK
+
+ 0x0850 mn-Mong-CN, reserved
+
+ 0x0851 bo-BT, reserved
+
+ 0x0859 sd-Arab-PK
+
+ 0x085D iu-Latn-CA
+
+ 0x085F tzm-Latn-DZ
+
+ 0x0860 ks-Deva-IN
+
+ 0x0861 ne-IN
+
+ 0x0867 ff-Latn-SN
+
+ 0x086B quz-EC
+
+ 0x0873 ti-ER
+
+ 0x09FF qps-plocm
+
+ 0x0C00 Locale without assigned LCID if the current user default locale. See section 2.2.1.
+
+
+ 19 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x0C01 ar-EG
+
+ 0x0C04 zh-HK
+
+ 0x0C07 de-AT
+
+ 0x0C09 en-AU
+
+ 0x0C0A es-ES
+
+ 0x0C0C fr-CA
+
+ 0x0C1A sr-Cyrl-CS
+
+ 0x0C3B se-FI
+
+ 0x0C50 mn-Mong-MN
+
+ 0x0C51 dz-BT
+
+ 0x0C5F tmz-MA, reserved
+
+ 0x0C6b quz-PE
+
+ 0x1000 Locale without assigned LCID if the current user default locale. See section 2.2.1.
+
+ 0x1001 ar-LY
+
+ 0x1004 zh-SG
+
+ 0x1007 de-LU
+
+ 0x1009 en-CA
+
+ 0x100A es-GT
+
+ 0x100C fr-CH
+
+ 0x101A hr-BA
+
+ 0x103B smj-NO
+
+ 0x105F tzm-Tfng-MA
+
+ 0x1401 ar-DZ
+
+ 0x1404 zh-MO
+
+ 0x1407 de-LI
+
+ 0x1409 en-NZ
+
+ 0x140A es-CR
+
+ 0x140C fr-LU
+
+ 0x141A bs-Latn-BA
+
+ 0x143B smj-SE
+
+ 0x1801 ar-MA
+
+ 0x1809 en-IE
+
+
+ 20 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x180A es-PA
+
+ 0x180C fr-MC
+
+ 0x181A sr-Latn-BA
+
+ 0x183B sma-NO
+
+ 0x1C01 ar-TN
+
+ 0x1C09 en-ZA
+
+ 0x1C0A es-DO
+
+ 0x1C0C fr-029
+
+ 0x1C1A sr-Cyrl-BA
+
+ 0x1C3B sma-SE
+
+ 0x2000 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1.
+
+ 0x2001 ar-OM
+
+ 0x2008 Neither defined nor reserved
+
+ 0x2009 en-JM
+
+ 0x200A es-VE
+
+ 0x200C fr-RE
+
+ 0x201A bs-Cyrl-BA
+
+ 0x203B sms-FI
+
+ 0x2400 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1.
+
+ 0x2401 ar-YE
+
+ 0x2409 en-029, reserved
+
+ 0x240A es-CO
+
+ 0x240C fr-CD
+
+ 0x241A sr-Latn-RS
+
+ 0x243B smn-FI
+
+ 0x2800 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1.
+
+ 0x2801 ar-SY
+
+ 0x2809 en-BZ
+
+ 0x280A es-PE
+
+ 0x280C fr-SN
+
+ 0x281A sr-Cyrl-RS
+
+ 0x2C00 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1.
+
+
+ 21 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x2C01 ar-JO
+
+ 0x2C09 en-TT
+
+ 0x2C0A es-AR
+
+ 0x2C0C fr-CM
+
+ 0x2C1A sr-Latn-ME
+
+ 0x3000 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1.
+
+ 0x3001 ar-LB
+
+ 0x3009 en-ZW
+
+ 0x300A es-EC
+
+ 0x300C fr-CI
+
+ 0x301A sr-Cyrl-ME
+
+ 0x3400 Unassigned LCID locale temporarily assigned to LCID 0x3400. See section 2.2.1.
+
+ 0x3401 ar-KW
+
+ 0x3409 en-PH
+
+ 0x340A es-CL
+
+ 0x340C fr-ML
+
+ 0x3800 Unassigned LCID locale temporarily assigned to LCID 0x3800. See section 2.2.1.
+
+ 0x3801 ar-AE
+
+ 0x3809 en-ID, reserved
+
+ 0x380A es-UY
+
+ 0x380C fr-MA
+
+ 0x3C00 Unassigned LCID locale temporarily assigned to LCID 0x3C00. See section 2.2.1.
+
+ 0x3C01 ar-BH
+
+ 0x3C09 en-HK
+
+ 0x3C0A es-PY
+
+ 0x3C0C fr-HT
+
+ 0x4000 Unassigned LCID locale temporarily assigned to LCID 0x4000. See section 2.2.1.
+
+ 0x4001 ar-QA
+
+ 0x4009 en-IN
+
+ 0x400A es-BO
+
+ 0x4400 Unassigned LCID locale temporarily assigned to LCID 0x4400. See section 2.2.1.
+
+ 0x4401 ar-Ploc-SA, reserved
+
+
+ 22 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x4409 en-MY
+
+ 0x440A es-SV
+
+ 0x4800 Unassigned LCID locale temporarily assigned to LCID 0x4800. See section 2.2.1.
+
+ 0x4801 ar-145, reserved
+
+ 0x4809 en-SG
+
+ 0x480A es-HN
+
+ 0x4C00 Unassigned LCID locale temporarily assigned to LCID 0x4C00. See section 2.2.1.
+
+ 0x4C09 en-AE
+
+ 0x4C0A es-NI
+
+ 0x5009 en-BH, reserved
+
+ 0x500A es-PR
+
+ 0x5409 en-EG, reserved
+
+ 0x540A es-US
+
+ 0x5809 en-JO, reserved
+
+ 0x580A es-419, reserved
+
+ 0x5C09 en-KW, reserved
+
+ 0x5C0A es-CU
+
+ 0x6009 en-TR, reserved
+
+ 0x6409 en-YE, reserved
+
+ 0x641A bs-Cyrl
+
+ 0x681A bs-Latn
+
+ 0x6C1A sr-Cyrl
+
+ 0x701A sr-Latn
+
+ 0x703B smn
+
+ 0x742C az-Cyrl
+
+ 0x743B sms
+
+ 0x7804 zh
+
+ 0x7814 nn
+
+ 0x781A bs
+
+ 0x782C az-Latn
+
+ 0x783B sma
+
+ 0x783F kk-Cyrl, reserved
+
+
+ 23 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language ID Language tag
+
+ 0x7843 uz-Cyrl
+
+ 0x7850 mn-Cyrl
+
+ 0x785D iu-Cans
+
+ 0x785F tzm-Tfng
+
+ 0x7C04 zh-Hant
+
+ 0x7C14 nb
+
+ 0x7C1A sr
+
+ 0x7C28 tg-Cyrl
+
+ 0x7C2E dsb
+
+ 0x7C3B smj
+
+ 0x7C3F kk-Latn, reserved
+
+ 0x7C43 uz-Latn
+
+ 0x7C46 pa-Arab
+
+ 0x7C50 mn-Mong
+
+ 0x7C59 sd-Arab
+
+ 0x7C5C chr-Cher
+
+ 0x7C5D iu-Latn
+
+ 0x7C5F tzm-Latn
+
+ 0x7C67 ff-Latn
+
+ 0x7C68 ha-Latn
+
+ 0x7C92 ku-Arab
+
+ 0xF2EE reserved
+
+ 0xE40C fr-015, reserved
+
+ 0xEEEE reserved
+
+
+Some locales have more than one method of sorting, such as by pronunciation or stroke count. The
+primary sort for each locale is provided by the identifiers in the preceding Language ID table.
+Alternate sorts can be selected by using one of the identifiers from the following table.
+
+ LCID Language tag (string name)
+
+ 0x0001007F x-IV-mathan (math alphanumeric sorting)
+
+ 0x00010407 de-DE_phoneb
+
+ 0x0001040E hu-HU_tchncl
+
+ 0x00010437 ka-GE_modern
+
+
+
+ 24 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ LCID Language tag (string name)
+
+ 0x00020804 zh-CN_stroke
+
+ 0x00021004 zh-SG_stroke
+
+ 0x00021404 zh-MO_stroke
+
+ 0x00030404 zh-TW_pronun
+
+ 0x00040404<9> zh-TW_radstr
+
+ 0x00040411 ja-JP_radstr
+
+ 0x00040C04<10> zh-HK_radstr
+
+ 0x00041404<11> zh-MO_radstr
+
+ 0x00050804<12> zh-CN_phoneb
+
+ 0x00051004<13> zh-SG_phoneb
+
+
+
+
+2.2.1 Locale Names without LCIDs
+
+Every locale name without an assigned LCID MAY be temporarily given one of the LCIDs in the
+following table, if the application requests an LCID.<14> These locale names include any valid
+[RFC5646] language tag.
+
+ Note: LCID assignments for Locale Names without LCIDs are temporary and are not suitable
+ for use across a protocol, or for interchange between processes or machines. These temporary
+ LCID assignments are also unsuitable for tagging persisted data as the meaning of the LCID
+ assignment will change over time.
+
+
+ Name Value Conditions
+
+ LOCALE_CUSTOM_USER_DEFAULT<15> 0x0C00 When an LCID without a permanent LCID
+ assignment is also the current user locale, the
+ protocol will respond with
+ LOCALE_CUSTOM_USER_DEFAULT for that locale.
+ This assignment persists until the user changes the
+ locale. Because the meaning changes over time,
+ applications are discouraged from persisting this
+ data. Though this value will likely refer to the same
+ locale for the lifetime of the current process, that is
+ not guaranteed. This assignment is a 1-to-1
+ relationship between this LCID and the user’s
+ current default locale name.
+
+
+
+
+ 25 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Name Value Conditions
+
+ Transient LCIDs<16> 0x2000, Some user configurations temporarily associate a
+ 0x2400, locale without a permanent LCID assignment with
+ 0x2800, one of these 12 transient LCIDs. This assignment is
+ 0x2C00, transient and it is not guaranteed; it will likely refer
+ 0x3000, to the same locale for the lifetime of the process.
+ 0x3400, However, this assignment will differ for other users
+ 0x3800, on the machine, or other machines, and, as such,
+ 0x3C00, is unsuitable for use in protocols or persisted data.
+ 0x4000, This assignment is a temporary 1-to-1 relationship
+ 0x4400, between an LCID and a particular locale name and
+ 0x4800, 0x4C00 will round trip until that relationship changes.
+
+ LOCALE_CUSTOM_UNSPECIFIED<17> 0x1000 When an LCID is requested for a locale without a
+ permanent LCID assignment, nor a temporary
+ assignment as above, the protocol will respond
+ with LOCALE_CUSTOM_UNSPECIFIED for all such
+ locales. Because this single value is used for
+ numerous possible locale names, it is impossible to
+ round trip this locale, even temporarily.
+ Applications should discard this value as soon as
+ possible and never persist it. If the system is
+ forced to respond to a request for
+ LCID_CUSTOM_UNSPECIFIED, it will fall back to
+ the current user locale. This is often incorrect but
+ may prevent an application or component from
+ failing. As the meaning of this temporary LCID is
+ unstable, it should never be used for interchange
+ or persisted data. This is a 1-to-many relationship
+ that is very unstable.
+
+
+
+
+ 26 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ 3 Structure Examples
+The following are examples of LCID values.
+
+ LCID Language tag (string name) Type
+
+ 0x00000075 haw neutral locale
+
+ 0x00000409 en-US specific locale
+
+ 0x00010407 de-DE_phoneb alternate sort for locale
+
+
+
+
+ 27 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ 4 Security Considerations
+None.
+
+
+
+
+ 28 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ 5 Appendix A: Product Behavior
+The information in this specification is applicable to the following Microsoft products or supplemental
+software. References to product versions include updates to those products.
+
+The terms "earlier" and "later", when used with a product version, refer to either all preceding
+versions or all subsequent versions, respectively. The term "through" refers to the inclusive range of
+versions. Applicable Microsoft products are listed chronologically in this section.
+
+Windows Client
+
+ Windows NT operating system
+
+ Windows 2000 operating system
+
+ Windows XP operating system
+
+ Windows Vista operating system
+
+ Windows 7 operating system
+
+ Windows 8 operating system
+
+ Windows 8.1 operating system
+
+ Windows 10 operating system
+
+ Windows 11 operating system
+
+Windows Server
+
+ Windows NT
+
+ Windows 2000
+
+ Windows Server 2003 operating system
+
+ Windows Server 2008 R2 operating system
+
+ Windows Server 2012 operating system
+
+ Windows Server 2012 R2 operating system
+
+ Windows Server 2016 operating system
+
+ Windows Server operating system
+
+ Windows Server 2019 operating system
+
+ Windows Server 2022 operating system
+
+ Windows Server 2025 operating system
+
+Exceptions, if any, are noted in this section. If an update version, service pack or Knowledge Base
+(KB) number appears with a product name, the behavior changed in that update. The new behavior
+also applies to subsequent updates unless otherwise specified. If a product edition appears with the
+product version, behavior is different in that product edition.
+
+Unless otherwise specified, any statement of optional behavior in this specification that is prescribed
+using the terms "SHOULD" or "SHOULD NOT" implies product behavior in accordance with the
+
+
+
+ 29 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ SHOULD or SHOULD NOT prescription. Unless otherwise specified, the term "MAY" implies that the
+product does not follow the prescription.
+
+<1> Section 2.1: Enabled Languages Kit (ELK) refers to a set of locales that is available through a
+web download. Everything that is related to a locale is available from an ELK package (including
+information on data formatting, such as date and time, font, keyboard layout, sorting, and currency
+information). Additional LCID support is available through a separate ELK package for Windows XP and
+Windows Vista clients and for Windows Server 2003 and Windows Server 2008 operating system
+servers.
+
+<2> Section 2.1: In Windows, locales are primarily identified with numeric LCIDs.
+
+<3> Section 2.1: Windows Server 2003 supports all languages defined for Windows 95 operating
+system, Windows 98 operating system, Windows Millennium Edition operating system, Windows NT
+3.51 operating system, Windows NT 4.0 operating system, Windows 2000, Windows XP, and Windows
+Server 2003 through the ELK.
+
+<4> Section 2.2: Supported only on Windows NT client and server releases.
+
+<5> Section 2.2: Supported only on Windows NT client and server releases.
+
+<6> Section 2.2: Supported only on Windows NT client and server releases.
+
+<7> Section 2.2: Supported only on Windows 7.
+
+<8> Section 2.2: The following table shows Language IDs and the versions of Windows in which they
+were first made available. Language IDs are not assigned for all Language tags, please see section 1.3
+for further details.
+
+Supported Versions Key
+
+ Release key Supported versions
+
+ Release A First available in Windows NT 3.51. Supported in all later versions.
+
+ Release B First available in Windows NT Server 4.0 operating system. Supported in all later versions.
+
+ Release C First available in Windows 2000. Supported in all later versions.
+
+ Release D First available in Windows XP and Windows Server 2003. Supported in all later versions.
+
+ Release E1 First available in Windows XP ELK v1 for Windows XP SP2, Windows Server 2003, Windows
+ Vista, and Windows Server 2008. Supported in all later client and server versions of Windows.
+
+ Release E2 First available in Windows XP ELK v2 for Windows XP SP2, Windows Server 2003, Windows
+ Vista, and Windows Server 2008. Supported in all later client and server versions of Windows.
+
+ Release V First available in Windows Server 2008 and Windows Vista. Supported in all later versions.
+
+ Release 7 First available in Windows 7 and Windows Server 2008 R2. Supported in all later versions.
+
+ Release 8 First available in Windows 8 and Windows Server 2012. Supported in all later versions
+
+ Release 8.1 First available in Windows 8.1 and Windows Server 2012 R2. Supported in all later versions.
+
+ Release 10 First available in Windows 10 and Windows Server 2016. Supported in all later versions.
+
+ Release 10.1 First available in Windows 10 v1607 operating system and Windows Server 2016. Supported
+ in all later versions.
+
+ Release 10.2 First available in Windows 10 v1703 operating system. Supported in all later versions.
+
+ Release 10.3 First available in Windows 10 v1709 operating system and Windows Server operating system.
+
+
+ 30 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Release key Supported versions
+
+ Supported in all later versions.
+
+ Release 10.4 First available in Windows 10 v1903 operating system and Windows Server v1903 operating
+ system. Supported in all later versions.
+
+ Release 10.5 First available in Windows 10 v2004 operating system and Windows Server v2004 operating
+ system. Supported in all later versions.
+
+
+
+
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Afar 0x1000 aa Release 10
+
+ Afar Djibouti 0x1000 aa-DJ Release 10
+
+ Afar Eritrea 0x1000 aa-ER Release 10
+
+ Afar Ethiopia 0x1000 aa-ET Release 10
+
+ Afrikaans 0x0036 af Release 7
+
+ Afrikaans Namibia 0x1000 af-NA Release 10
+
+ Afrikaans South Africa 0x0436 af-ZA Release B
+
+ Aghem 0x1000 agq Release 10
+
+ Aghem Cameroon 0x1000 agq-CM Release 10
+
+ Akan 0x1000 ak Release 10
+
+ Akan Ghana 0x1000 ak-GH Release 10
+
+ Albanian 0x001C sq Release 7
+
+ Albanian Albania 0x041C sq-AL Release B
+
+ Albanian North Macedonia 0x1000 sq-MK Release 10
+
+ Alsatian 0x0084 gsw Release 7
+
+ Alsatian France 0x0484 gsw-FR Release V
+
+ Alsatian Liechtenstein 0x1000 gsw-LI Release 10
+
+ Alsatian Switzerland 0x1000 gsw-CH Release 10
+
+ Amharic 0x005E am Release 7
+
+ Amharic Ethiopia 0x045E am-ET Release V
+
+ Arabic 0x0001 ar Release 7
+
+ Arabic Algeria 0x1401 ar-DZ Release B
+
+ Arabic Bahrain 0x3C01 ar-BH Release B
+
+ Arabic Chad 0x1000 ar-TD Release 10
+
+ Arabic Comoros 0x1000 ar-KM Release 10
+
+
+ 31 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Arabic Djibouti 0x1000 ar-DJ Release 10
+
+ Arabic Egypt 0x0c01 ar-EG Release B
+
+ Arabic Eritrea 0x1000 ar-ER Release 10
+
+ Arabic Iraq 0x0801 ar-IQ Release B
+
+ Arabic Israel 0x1000 ar-IL Release 10
+
+ Arabic Jordan 0x2C01 ar-JO Release B
+
+ Arabic Kuwait 0x3401 ar-KW Release B
+
+ Arabic Lebanon 0x3001 ar-LB Release B
+
+ Arabic Libya 0x1001 ar-LY Release B
+
+ Arabic Mauritania 0x1000 ar-MR Release 10
+
+ Arabic Morocco 0x1801 ar-MA Release B
+
+ Arabic Oman 0x2001 ar-OM Release B
+
+ Arabic Palestinian Authority 0x1000 ar-PS Release 10
+
+ Arabic Qatar 0x4001 ar-QA Release B
+
+ Arabic Saudi Arabia 0x0401 ar-SA Release B
+
+ Arabic Somalia 0x1000 ar-SO Release 10
+
+ Arabic South Sudan 0x1000 ar-SS Release 10
+
+ Arabic Sudan 0x1000 ar-SD Release 10
+
+ Arabic Syria 0x2801 ar-SY Release B
+
+ Arabic Tunisia 0x1C01 ar-TN Release B
+
+ Arabic U.A.E. 0x3801 ar-AE Release B
+
+ Arabic World 0x1000 ar-001 Release 10
+
+ Arabic Yemen 0x2401 ar-YE Release B
+
+ Armenian 0x002B hy Release 7
+
+ Armenian Armenia 0x042B hy-AM Release C
+
+ Assamese 0x004D as Release 7
+
+ Assamese India 0x044D as-IN Release V
+
+ Asturian 0x1000 ast Release 10
+
+ Asturian Spain 0x1000 ast-ES Release 10
+
+ Asu 0x1000 asa Release 10
+
+ Asu Tanzania 0x1000 asa-TZ Release 10
+
+
+
+ 32 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Azerbaijani (Cyrillic) 0x742C az-Cyrl Windows 7
+
+ Azerbaijani (Cyrillic) Azerbaijan 0x082C az-Cyrl-AZ Release C
+
+ Azerbaijani (Latin) 0x002C az Release 7
+
+ Azerbaijani (Latin) 0x782C az-Latn Windows 7
+
+ Azerbaijani (Latin) Azerbaijan 0x042C az-Latn-AZ Release C
+
+ Bafia 0x1000 ksf Release 10
+
+ Bafia Cameroon 0x1000 ksf-CM Release 10
+
+ Bamanankan 0x1000 bm Release 10
+
+ Bamanankan (Latin) Mali 0x1000 bm-Latn-ML Release 10
+
+ Bangla 0x0045 bn Release 7
+
+ Bangla Bangladesh 0x0845 bn-BD Release V
+
+ Bangla India 0x0445 bn-IN Release E1
+
+ Basaa 0x1000 bas Release 10
+
+ Basaa Cameroon 0x1000 bas-CM Release 10
+
+ Bashkir 0x006D ba Release 7
+
+ Bashkir Russia 0x046D ba-RU Release V
+
+ Basque 0x002D eu Release 7
+
+ Basque Spain 0x042D eu-ES Release B
+
+ Belarusian 0x0023 be Release 7
+
+ Belarusian Belarus 0x0423 be-BY Release B
+
+ Bemba 0x1000 bem Release 10
+
+ Bemba Zambia 0x1000 bem-ZM Release 10
+
+ Bena 0x1000 bez Release 10
+
+ Bena Tanzania 0x1000 bez-TZ Release 10
+
+ Bhojpuri 0x1000 bho Release 11
+
+ Bhojpuri (Devanagari) 0x1000 bho-Deva Release 11
+
+ Bhojpuri (Devanagari) India 0x1000 bho-Deva-IN Release 11
+
+ Blin 0x1000 byn Release 10
+
+ Blin Eritrea 0x1000 byn-ER Release 10
+
+ Bodo 0x1000 brx Release 10
+
+ Bodo India 0x1000 brx-IN Release 10
+
+
+
+ 33 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Bosnian (Cyrillic) 0x641A bs-Cyrl Windows 7
+
+ Bosnian (Cyrillic) Bosnia and Herzegovina 0x201A bs-Cyrl-BA Release E1
+
+ Bosnian (Latin) 0x681A bs-Latn Windows 7
+
+ Bosnian (Latin) 0x781A bs Release 7
+
+ Bosnian (Latin) Bosnia and Herzegovina 0x141A bs-Latn-BA Release E1
+
+ Breton 0x007E br Release 7
+
+ Breton France 0x047E br-FR Release V
+
+ Bulgarian 0x0002 bg Release 7
+
+ Bulgarian Bulgaria 0x0402 bg-BG Release B
+
+ Burmese 0x0055 my Release 8.1
+
+ Burmese Myanmar 0x0455 my-MM Release 8.1
+
+ Catalan 0x0003 ca Release 7
+
+ Catalan Andorra 0x1000 ca-AD Release 10
+
+ Catalan France 0x1000 ca-FR Release 10
+
+ Catalan Italy 0x1000 ca-IT Release 10
+
+ Catalan Spain 0x0403 ca-ES Release B
+
+ Cebuano 0x1000 ceb Release 10.5
+
+ Cebuan (Latin) 0x1000 ceb-Latn Release 10.5
+
+ Cebuan (Latin) Philippines 0x1000 ceb-Latn-PH Release 10.5
+
+ Central Atlas Tamazight Morocco 0x045F tzm-Arab- Release 10
+ (Arabic) MA
+
+ Central Atlas Tamazight Morocco 0x1000 tzm-Latn- Release 10
+ (Latin) MA
+
+ Central Kurdish 0x0092 ku Release 8
+
+ Central Kurdish 0x7c92 ku-Arab Release 8
+
+ Central Kurdish Iraq 0x0492 ku-Arab-IQ Release 8
+
+ Chakma 0x1000 ccp Release 10.5
+
+ Chakma Chakma 0x1000 ccp-Cakm Release 10.5
+
+ Chakma Bangladesh 0x1000 ccp-Cakm- Release 10.5
+ BD
+
+ Chakma India 0x1000 ccp-Cakm- Release 10.5
+ IN
+
+ Chechen Russia 0x1000 ce-RU Release 10.1
+
+
+
+ 34 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Cherokee 0x005C chr Release 8
+
+ Cherokee 0x7c5C chr-Cher Release 8
+
+ Cherokee United States 0x045C chr-Cher-US Release 8
+
+ Chiga 0x1000 cgg Release 10
+
+ Chiga Uganda 0x1000 cgg-UG Release 10
+
+ Chinese (Simplified) 0x0004 zh-Hans Release A
+
+ Chinese (Simplified) 0x7804 zh Windows 7
+
+ Chinese (Simplified) People's Republic of China 0x0804 zh-CN Release A
+
+ Chinese (Simplified) Singapore 0x1004 zh-SG Release A
+
+ Chinese (Traditional) 0x7C04 zh-Hant Release A
+
+ Chinese (Traditional) Hong Kong S.A.R. 0x0C04 zh-HK Release A
+
+ Chinese (Traditional) Macao S.A.R. 0x1404 zh-MO Release D
+
+ Chinese (Traditional) Taiwan 0x0404 zh-TW Release A
+
+ Church Slavic Russia 0x1000 cu-RU Release 10.1
+
+ Chuvash 0x1000 cv Release 11
+
+ Chuvash (Cyrillic) 0x1000 cv-Cyrl Release 11
+
+ Chuvash (Cyrillic) Russia 0x1000 cv-Cyrl-RU Release 11
+
+ Congo Swahili 0x1000 swc Release 10
+
+ Congo Swahili Congo DRC 0x1000 swc-CD Release 10
+
+ Cornish 0x1000 kw Release 10
+
+ Cornish United Kingdom 0x1000 kw-GB Release 10
+
+ Corsican 0x0083 co Release 7
+
+ Corsican France 0x0483 co-FR Release V
+
+ Croatian 0x001A hr Release 7
+
+ Croatian Croatia 0x041A hr-HR Release A
+
+ Croatian (Latin) Bosnia and Herzegovina 0x101A hr-BA Release E1
+
+ Czech 0x0005 cs Release 7
+
+ Czech Czech Republic 0x0405 cs-CZ Release A
+
+ Danish 0x0006 da Release 7
+
+ Danish Denmark 0x0406 da-DK Release A
+
+ Danish Greenland 0x1000 da-GL Release 10
+
+
+
+ 35 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Dari 0x008C prs Release 7
+
+ Dari Afghanistan 0x048C prs-AF Release V
+
+ Divehi 0x0065 dv Release 7
+
+ Divehi Maldives 0x0465 dv-MV Release D
+
+ Duala 0x1000 dua Release 10
+
+ Duala Cameroon 0x1000 dua-CM Release 10
+
+ Dutch 0x0013 nl Release 7
+
+ Dutch Aruba 0x1000 nl-AW Release 10
+
+ Dutch Belgium 0x0813 nl-BE Release A
+
+ Dutch Bonaire, Sint Eustatius and Saba 0x1000 nl-BQ Release 10
+
+ Dutch Curaçao 0x1000 nl-CW Release 10
+
+ Dutch Netherlands 0x0413 nl-NL Release A
+
+ Dutch Sint Maarten 0x1000 nl-SX Release 10
+
+ Dutch Suriname 0x1000 nl-SR Release 10
+
+ Dzongkha 0x1000 dz Release 10
+
+ Dzongkha Bhutan 0x0C51 dz-BT Release 10
+
+ Embu 0x1000 ebu Release 10
+
+ Embu Kenya 0x1000 ebu-KE Release 10
+
+ English 0x0009 en Release 7
+
+ English American Samoa 0x1000 en-AS Release 10
+
+ English Anguilla 0x1000 en-AI Release 10
+
+ English Antigua and Barbuda 0x1000 en-AG Release 10
+
+ English Australia 0x0C09 en-AU Release A
+
+ English Austria 0x1000 en-AT Release 10.1
+
+ English Bahamas 0x1000 en-BS Release 10
+
+ English Barbados 0x1000 en-BB Release 10
+
+ English Belgium 0x1000 en-BE Release 10
+
+ English Belize 0x2809 en-BZ Release B
+
+ English Bermuda 0x1000 en-BM Release 10
+
+ English Botswana 0x1000 en-BW Release 10
+
+ English British Indian Ocean Territory 0x1000 en-IO Release 10
+
+
+
+ 36 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ English British Virgin Islands 0x1000 en-VG Release 10
+
+ English Burundi 0x1000 en-BI Release 10.1
+
+ English Cameroon 0x1000 en-CM Release 10
+
+ English Canada 0x1009 en-CA Release A
+
+ English Caribbean 0x2409 en-029 Release B
+
+ English Cayman Islands 0x1000 en-KY Release 10
+
+ English Christmas Island 0x1000 en-CX Release 10
+
+ English Cocos [Keeling] Islands 0x1000 en-CC Release 10
+
+ English Cook Islands 0x1000 en-CK Release 10
+
+ English Cyprus 0x1000 en-CY Release 10.1
+
+ English Denmark 0x1000 en-DK Release 10.1
+
+ English Dominica 0x1000 en-DM Release 10
+
+ English Eritrea 0x1000 en-ER Release 10
+
+ English Europe 0x1000 en-150 Release 10
+
+ English Falkland Islands 0x1000 en-FK Release 10
+
+ English Finland 0x1000 en-FI Release 10.1
+
+ English Fiji 0x1000 en-FJ Release 10
+
+ English Gambia 0x1000 en-GM Release 10
+
+ English Germany 0x1000 en-DE Release 10.1
+
+ English Ghana 0x1000 en-GH Release 10
+
+ English Gibraltar 0x1000 en-GI Release 10
+
+ English Grenada 0x1000 en-GD Release 10
+
+ English Guam 0x1000 en-GU Release 10
+
+ English Guernsey 0x1000 en-GG Release 10
+
+ English Guyana 0x1000 en-GY Release 10
+
+ English Hong Kong 0x3C09 en-HK Release 8.1
+
+ English India 0x4009 en-IN Release V
+
+ English Ireland 0x1809 en-IE Release A
+
+ English Isle of Man 0x1000 en-IM Release 10
+
+ English Israel 0x1000 en-IL Release 10.1
+
+ English Jamaica 0x2009 en-JM Release B
+
+
+
+ 37 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ English Jersey 0x1000 en-JE Release 10
+
+ English Kenya 0x1000 en-KE Release 10
+
+ English Kiribati 0x1000 en-KI Release 10
+
+ English Lesotho 0x1000 en-LS Release 10
+
+ English Liberia 0x1000 en-LR Release 10
+
+ English Macao SAR 0x1000 en-MO Release 10
+
+ English Madagascar 0x1000 en-MG Release 10
+
+ English Malawi 0x1000 en-MW Release 10
+
+ English Malaysia 0x4409 en-MY Release V
+
+ English Maldives 0x1000 en-MV Release 11
+
+ English Malta 0x1000 en-MT Release 10
+
+ English Marshall Islands 0x1000 en-MH Release 10
+
+ English Mauritius 0x1000 en-MU Release 10
+
+ English Micronesia 0x1000 en-FM Release 10
+
+ English Montserrat 0x1000 en-MS Release 10
+
+ English Namibia 0x1000 en-NA Release 10
+
+ English Nauru 0x1000 en-NR Release 10
+
+ English Netherlands 0x1000 en-NL Release 10.1
+
+ English New Zealand 0x1409 en-NZ Release A
+
+ English Nigeria 0x1000 en-NG Release 10
+
+ English Niue 0x1000 en-NU Release 10
+
+ English Norfolk Island 0x1000 en-NF Release 10
+
+ English Northern Mariana Islands 0x1000 en-MP Release 10
+
+ English Pakistan 0x1000 en-PK Release 10
+
+ English Palau 0x1000 en-PW Release 10
+
+ English Papua New Guinea 0x1000 en-PG Release 10
+
+ English Pitcairn Islands 0x1000 en-PN Release 10
+
+ English Puerto Rico 0x1000 en-PR Release 10
+
+ English Republic of the Philippines 0x3409 en-PH Release C
+
+ English Rwanda 0x1000 en-RW Release 10
+
+ English Saint Kitts and Nevis 0x1000 en-KN Release 10
+
+
+
+ 38 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ English Saint Lucia 0x1000 en-LC Release 10
+
+ English Saint Vincent and the Grenadines 0x1000 en-VC Release 10
+
+ English Samoa 0x1000 en-WS Release 10
+
+ English Seychelles 0x1000 en-SC Release 10
+
+ English Sierra Leone 0x1000 en-SL Release 10
+
+ English Singapore 0x4809 en-SG Release V
+
+ English Sint Maarten 0x1000 en-SX Release 10
+
+ English Slovenia 0x1000 en-SI Release 10.1
+
+ English Solomon Islands 0x1000 en-SB Release 10
+
+ English South Africa 0x1C09 en-ZA Release B
+
+ English South Sudan 0x1000 en-SS Release 10
+
+ English St Helena, Ascension, Tristan da 0x1000 en-SH Release 10
+ Cunha
+
+ English Sudan 0x1000 en-SD Release 10
+
+ English Swaziland 0x1000 en-SZ Release 10
+
+ English Sweden 0x1000 en-SE Release 10.1
+
+ English Switzerland 0x1000 en-CH Release 10.1
+
+ English Tanzania 0x1000 en-TZ Release 10
+
+ English Tokelau 0x1000 en-TK Release 10
+
+ English Tonga 0x1000 en-TO Release 10
+
+ English Trinidad and Tobago 0x2c09 en-TT Release B
+
+ English Turks and Caicos Islands 0x1000 en-TC Release 10
+
+ English Tuvalu 0x1000 en-TV Release 10
+
+ English Uganda 0x1000 en-UG Release 10
+
+ English United Arab Emirates 0x4C09 en-AE Release 10.5
+
+ English United Kingdom 0x0809 en-GB Release A
+
+ English United States 0x0409 en-US Release A
+
+ English US Minor Outlying Islands 0x1000 en-UM Release 10
+
+ English US Virgin Islands 0x1000 en-VI Release 10
+
+ English Vanuatu 0x1000 en-VU Release 10
+
+ English World 0x1000 en-001 Release 10
+
+ English Zambia 0x1000 en-ZM Release 10
+
+
+ 39 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ English Zimbabwe 0x3009 en-ZW Release C
+
+ Esperanto 0x1000 eo Release 10
+
+ Esperanto World 0x1000 eo-001 Release 10
+
+ Estonian 0x0025 et Release 7
+
+ Estonian Estonia 0x0425 et-EE Release B
+
+ Ewe 0x1000 ee Release 10
+
+ Ewe Ghana 0x1000 ee-GH Release 10
+
+ Ewe Togo 0x1000 ee-TG Release 10
+
+ Ewondo 0x1000 ewo Release 10
+
+ Ewondo Cameroon 0x1000 ewo-CM Release 10
+
+ Faroese 0x0038 fo Release 7
+
+ Faroese Denmark 0x1000 fo-DK Release 10.1
+
+ Faroese Faroe Islands 0x0438 fo-FO Release B
+
+ Filipino 0x0064 fil Release 7
+
+ Filipino Philippines 0x0464 fil-PH Release E2
+
+ Finnish 0x000B fi Release 7
+
+ Finnish Finland 0x040B fi-FI Release A
+
+ French 0x000C fr Release 7
+
+ French Algeria 0x1000 fr-DZ Release 10
+
+ French Belgium 0x080C fr-BE Release A
+
+ French Benin 0x1000 fr-BJ Release 10
+
+ French Burkina Faso 0x1000 fr-BF Release 10
+
+ French Burundi 0x1000 fr-BI Release 10
+
+ French Cameroon 0x2c0C fr-CM Release 8.1
+
+ French Canada 0x0c0C fr-CA Release A
+
+ French Caribbean 0x1C0C fr-029 Release 10
+
+ French Central African Republic 0x1000 fr-CF Release 10
+
+ French Chad 0x1000 fr-TD Release 10
+
+ French Comoros 0x1000 fr-KM Release 10
+
+ French Congo 0x1000 fr-CG Release 10
+
+ French Congo, DRC 0x240C fr-CD Release 8.1
+
+
+
+ 40 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ French Côte d'Ivoire 0x300C fr-CI Release 8.1
+
+ French Djibouti 0x1000 fr-DJ Release 10
+
+ French Equatorial Guinea 0x1000 fr-GQ Release 10
+
+ French France 0x040C fr-FR Release A
+
+ French French Guiana 0x1000 fr-GF Release 10
+
+ French French Polynesia 0x1000 fr-PF Release 10
+
+ French Gabon 0x1000 fr-GA Release 10
+
+ French Guadeloupe 0x1000 fr-GP Release 10
+
+ French Guinea 0x1000 fr-GN Release 10
+
+ French Haiti 0x3c0C fr-HT Release 8.1
+
+ French Luxembourg 0x140C fr-LU Release A
+
+ French Madagascar 0x1000 fr-MG Release 10
+
+ French Mali 0x340C fr-ML Release 8.1
+
+ French Martinique 0x1000 fr-MQ Release 10
+
+ French Mauritania 0x1000 fr-MR Release 10
+
+ French Mauritius 0x1000 fr-MU Release 10
+
+ French Mayotte 0x1000 fr-YT Release 10
+
+ French Morocco 0x380C fr-MA Release 8.1
+
+ French New Caledonia 0x1000 fr-NC Release 10
+
+ French Niger 0x1000 fr-NE Release 10
+
+ French Principality of Monaco 0x180C fr-MC Release A
+
+ French Reunion 0x200C fr-RE Release 8.1
+
+ French Rwanda 0x1000 fr-RW Release 10
+
+ French Saint Barthélemy 0x1000 fr-BL Release 10
+
+ French Saint Martin 0x1000 fr-MF Release 10
+
+ French Saint Pierre and Miquelon 0x1000 fr-PM Release 10
+
+ French Senegal 0x280C fr-SN Release 8.1
+
+ French Seychelles 0x1000 fr-SC Release 10
+
+ French Switzerland 0x100C fr-CH Release A
+
+ French Syria 0x1000 fr-SY Release 10
+
+ French Togo 0x1000 fr-TG Release 10
+
+
+
+ 41 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ French Tunisia 0x1000 fr-TN Release 10
+
+ French Vanuatu 0x1000 fr-VU Release 10
+
+ French Wallis and Futuna 0x1000 fr-WF Release 10
+
+ Frisian 0x0062 fy Release 7
+
+ Frisian Netherlands 0x0462 fy-NL Release E2
+
+ Friulian 0x1000 fur Release 10
+
+ Friulian Italy 0x1000 fur-IT Release 10
+
+ Fulah 0x0067 ff Release 8
+
+ Fulah (Latin) 0x7C67 ff-Latn Release 8
+
+ Fulah (Latin) Burkina Faso 0x1000 ff-Latn-BF Release 10.4
+
+ Fulah Cameroon 0x1000 ff-CM Release 10
+
+ Fulah (Latin) Cameroon 0x1000 ff-Latn-CM Release 10.4
+
+ Fulah (Latin) Gambia 0x1000 ff-Latn-GM Release 10.4
+
+ Fulah (Latin) Ghana 0x1000 ff-Latn-GH Release 10.4
+
+ Fulah Guinea 0x1000 ff-GN Release 10
+
+ Fulah (Latin) Guinea 0x1000 ff-Latn-GN Release 10.4
+
+ Fulah (Latin) Guinea-Bissau 0x1000 ff-Latn-GW Release 10.4
+
+ Fulah (Latin) Liberia 0x1000 ff-Latn-LR Release 10.4
+
+ Fulah Mauritania 0x1000 ff-MR Release 10
+
+ Fulah (Latin) Mauritania 0x1000 ff-Latn-MR Release 10.4
+
+ Fulah (Latin) Niger 0x1000 ff-Latn-NE Release 10.4
+
+ Fulah Nigeria 0x0467 ff-NG Release 10
+
+ Fulah (Latin) Nigeria 0x0467 ff-Latn-NG Release 10.4
+
+ Fulah Senegal 0x0867 ff-Latn-SN Release 8
+
+ Fulah (Latin) Sierra Leone 0x1000 ff-Latn-SL Release 10.4
+
+ Galician 0x0056 gl Release 7
+
+ Galician Spain 0x0456 gl-ES Release D
+
+ Ganda 0x1000 lg Release 10
+
+ Ganda Uganda 0x1000 lg-UG Release 10
+
+ Georgian 0x0037 ka Release 7
+
+ Georgian Georgia 0x0437 ka-GE Release C
+
+
+
+ 42 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ German 0x0007 de Release 7
+
+ German Austria 0x0C07 de-AT Release A
+
+ German Belgium 0x1000 de-BE Release 10
+
+ German Germany 0x0407 de-DE Release A
+
+ German Italy 0x1000 de-IT Release 10.2
+
+ German Liechtenstein 0x1407 de-LI Release B
+
+ German Luxembourg 0x1007 de-LU Release B
+
+ German Switzerland 0x0807 de-CH Release A
+
+ Greek 0x0008 el Release 7
+
+ Greek Cyprus 0x1000 el-CY Release 10
+
+ Greek Greece 0x0408 el-GR Release A
+
+ Greenlandic 0x006F kl Release 7
+
+ Greenlandic Greenland 0x046F kl-GL Release V
+
+ Guarani 0x0074 gn Release 8.1
+
+ Guarani Paraguay 0x0474 gn-PY Release 8.1
+
+ Gujarati 0x0047 gu Release 7
+
+ Gujarati India 0x0447 gu-IN Release D
+
+ Gusii 0x1000 guz Release 10
+
+ Gusii Kenya 0x1000 guz-KE Release 10
+
+ Haryanvi 0x1000 bgc Release 11
+
+ Haryanvi (Devanagari) 0x1000 bgc-Deva Release 11
+
+ Haryanvi (Devanagari) India 0x1000 bgc-Deva-IN Release 11
+
+ Hausa (Latin) 0x0068 ha Release 7
+
+ Hausa (Latin) 0x7C68 ha-Latn Windows 7
+
+ Hausa (Latin) Ghana 0x1000 ha-Latn-GH Release 10
+
+ Hausa (Latin) Niger 0x1000 ha-Latn-NE Release 10
+
+ Hausa (Latin) Nigeria 0x0468 ha-Latn-NG Release V
+
+ Hawaiian 0x0075 haw Release 8
+
+ Hawaiian United States 0x0475 haw-US Release 8
+
+ Hebrew 0x000D he Release 7
+
+ Hebrew Israel 0x040D he-IL Release B
+
+
+
+ 43 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Hindi 0x0039 hi Release 7
+
+ Hindi India 0x0439 hi-IN Release C
+
+ Hindi (Latin) 0x1000 hi-Latn Release 11
+
+ Hindi (Latin) India 0x1000 hi-Latn-IN Release 11
+
+ Hungarian 0x000E hu Release 7
+
+ Hungarian Hungary 0x040E hu-HU Release A
+
+ Icelandic 0x000F is Release 7
+
+ Icelandic Iceland 0x040F is-IS Release A
+
+ Igbo 0x0070 ig Release 7
+
+ Igbo Nigeria 0x0470 ig-NG Release V
+
+ Indonesian 0x0021 id Release 7
+
+ Indonesian Indonesia 0x0421 id-ID Release B
+
+ Interlingua 0x1000 ia Release 10
+
+ Interlingua France 0x1000 ia-FR Release 10
+
+ Interlingua World 0x1000 ia-001 Release 10
+
+ Inuktitut (Latin) 0x005D iu Release 7
+
+ Inuktitut (Latin) 0x7C5D iu-Latn Windows 7
+
+ Inuktitut (Latin) Canada 0x085D iu-Latn-CA Release E2
+
+ Inuktitut (Syllabics) 0x785D iu-Cans Windows 7
+
+ Inuktitut (Syllabics) Canada 0x045d iu-Cans-CA Release V
+
+ Irish 0x003C ga Windows 7
+
+ Irish Ireland 0x083C ga-IE Release E2
+
+ Italian 0x0010 it Release 7
+
+ Italian Italy 0x0410 it-IT Release A
+
+ Italian San Marino 0x1000 it-SM Release 10
+
+ Italian Switzerland 0x0810 it-CH Release A
+
+ Italian Vatican City 0x1000 it-VA Release 10.3
+
+ Japanese 0x0011 ja Release 7
+
+ Japanese Japan 0x0411 ja-JP Release A
+
+ Javanese 0x1000 jv Release 8.1
+
+ Javanese Latin 0x1000 jv-Latn Release 8.1
+
+
+
+ 44 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Javanese Latin, Indonesia 0x1000 jv-Latn-ID Release 8.1
+
+ Jola-Fonyi 0x1000 dyo Release 10
+
+ Jola-Fonyi Senegal 0x1000 dyo-SN Release 10
+
+ Kabuverdianu 0x1000 kea Release 10
+
+ Kabuverdianu Cabo Verde 0x1000 kea-CV Release 10
+
+ Kabyle 0x1000 kab Release 10
+
+ Kabyle Algeria 0x1000 kab-DZ Release 10
+
+ Kaingang 0x1000 kgp Release 11
+
+ Kaingang (Latin) 0x1000 kgp-Latn Release 11
+
+ Kaingang (Latin) Brazil 0x1000 kgp-Latn-BR Release 11
+
+ Kako 0x1000 kkj Release 10
+
+ Kako Cameroon 0x1000 kkj-CM Release 10
+
+ Kalenjin 0x1000 kln Release 10
+
+ Kalenjin Kenya 0x1000 kln-KE Release 10
+
+ Kamba 0x1000 kam Release 10
+
+ Kamba Kenya 0x1000 kam-KE Release 10
+
+ Kannada 0x004B kn Release 7
+
+ Kannada India 0x044B kn-IN Release D
+
+ Kanuri (Latin) Nigeria 0x0471 kr-Latn-NG Release 10
+
+ Kashmiri 0x0060 ks Release 10
+
+ Kashmiri Perso-Arabic 0x0460 ks-Arab Release 10
+
+ Kashmiri Perso-Arabic 0x1000 ks-Arab-IN Release 10
+
+ Kashmiri (Devanagari) India 0x0860 ks-Deva-IN Release 10
+
+ Kazakh 0x003F kk Release 7
+
+ Kazakh Kazakhstan 0x043F kk-KZ Release C
+
+ Khmer 0x0053 km Release 7
+
+ Khmer Cambodia 0x0453 km-KH Release V
+
+ K'iche 0x0086 quc Release 10
+
+ K'iche Guatemala 0x0486 quc-Latn-GT Release 10
+
+ Kikuyu 0x1000 ki Release 10
+
+ Kikuyu Kenya 0x1000 ki-KE Release 10
+
+
+
+ 45 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Kinyarwanda 0x0087 rw Release 7
+
+ Kinyarwanda Rwanda 0x0487 rw-RW Release V
+
+ Kiswahili 0x0041 sw Release 7
+
+ Kiswahili Kenya 0x0441 sw-KE Release C
+
+ Kiswahili Tanzania 0x1000 sw-TZ Release 10
+
+ Kiswahili Uganda 0x1000 sw-UG Release 10
+
+ Konkani 0x0057 kok Release 7
+
+ Konkani India 0x0457 kok-IN Release C
+
+ Korean 0x0012 ko Release 7
+
+ Korean Korea 0x0412 ko-KR Release A
+
+ Korean North Korea 0x1000 ko-KP Release 10.1
+
+ Koyra Chiini 0x1000 khq Release 10
+
+ Koyra Chiini Mali 0x1000 khq-ML Release 10
+
+ Koyraboro Senni 0x1000 ses Release 10
+
+ Koyraboro Senni Mali 0x1000 ses-ML Release 10
+
+ Kwasio 0x1000 nmg Release 10
+
+ Kwasio Cameroon 0x1000 nmg-CM Release 10
+
+ Kyrgyz 0x0040 ky Release 7
+
+ Kyrgyz Kyrgyzstan 0x0440 ky-KG Release D
+
+ Kurdish Perso-Arabic, Iran 0x1000 ku-Arab-IR Release 10.1
+
+ Lakota 0x1000 lkt Release 10
+
+ Lakota United States 0x1000 lkt-US Release 10
+
+ Langi 0x1000 lag Release 10
+
+ Langi Tanzania 0x1000 lag-TZ Release 10
+
+ Lao 0x0054 lo Release 7
+
+ Lao Lao P.D.R. 0x0454 lo-LA Release V
+
+ Latin Vatican City 0x0476 la-VA Release 10.5
+
+ Latvian 0x0026 lv Release 7
+
+ Latvian Latvia 0x0426 lv-LV Release B
+
+ Lingala 0x1000 ln Release 10
+
+ Lingala Angola 0x1000 ln-AO Release 10
+
+
+
+ 46 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Lingala Central African Republic 0x1000 ln-CF Release 10
+
+ Lingala Congo 0x1000 ln-CG Release 10
+
+ Lingala Congo DRC 0x1000 ln-CD Release 10
+
+ Lithuanian 0x0027 lt Release 7
+
+ Lithuanian Lithuania 0x0427 lt-LT Release B
+
+ Low German 0x1000 nds Release 10.2
+
+ Low German Germany 0x1000 nds-DE Release 10.2
+
+ Low German Netherlands 0x1000 nds-NL Release 10.2
+
+ Lower Sorbian 0x7C2E dsb Windows 7
+
+ Lower Sorbian Germany 0x082E dsb-DE Release V
+
+ Luba-Katanga 0x1000 lu Release 10
+
+ Luba-Katanga Congo DRC 0x1000 lu-CD Release 10
+
+ Luo 0x1000 luo Release 10
+
+ Luo Kenya 0x1000 luo-KE Release 10
+
+ Luxembourgish 0x006E lb Release 7
+
+ Luxembourgish Luxembourg 0x046E lb-LU Release E2
+
+ Luyia 0x1000 luy Release 10
+
+ Luyia Kenya 0x1000 luy-KE Release 10
+
+ Macedonian 0x002F mk Release 7
+
+ Macedonian North Macedonia 0x042F mk-MK Release C
+
+ Machame 0x1000 jmc Release 10
+
+ Machame Tanzania 0x1000 jmc-TZ Release 10
+
+ Makhuwa-Meetto 0x1000 mgh Release 10
+
+ Makhuwa-Meetto Mozambique 0x1000 mgh-MZ Release 10
+
+ Makonde 0x1000 kde Release 10
+
+ Makonde Tanzania 0x1000 kde-TZ Release 10
+
+ Malagasy 0x1000 mg Release 8.1
+
+ Malagasy Madagascar 0x1000 mg-MG Release 8.1
+
+ Malay 0x003E ms Release 7
+
+ Malay Brunei Darussalam 0x083E ms-BN Release C
+
+ Malay Malaysia 0x043E ms-MY Release C
+
+
+
+ 47 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Malayalam 0x004C ml Release 7
+
+ Malayalam India 0x044C ml-IN Release E1
+
+ Maltese 0x003A mt Release 7
+
+ Maltese Malta 0x043A mt-MT Release E1
+
+ Manx 0x1000 gv Release 10
+
+ Manx Isle of Man 0x1000 gv-IM Release 10
+
+ Maori 0x0081 mi Release 7
+
+ Maori New Zealand 0x0481 mi-NZ Release E1
+
+ Mapudungun 0x007A arn Release 7
+
+ Mapudungun Chile 0x047A arn-CL Release E2
+
+ Marathi 0x004E mr Release 7
+
+ Marathi India 0x044E mr-IN Release C
+
+ Masai 0x1000 mas Release 10
+
+ Masai Kenya 0x1000 mas-KE Release 10
+
+ Masai Tanzania 0x1000 mas-TZ Release 10
+
+ Mazanderani Iran 0x1000 mzn-IR Release 10.1
+
+ Meru 0x1000 mer Release 10
+
+ Meru Kenya 0x1000 mer-KE Release 10
+
+ Meta' 0x1000 mgo Release 10
+
+ Meta' Cameroon 0x1000 mgo-CM Release 10
+
+ Mohawk 0x007C moh Release 7
+
+ Mohawk Canada 0x047C moh-CA Release E2
+
+ Mongolian (Cyrillic) 0x0050 mn Release 7
+
+ Mongolian (Cyrillic) 0x7850 mn-Cyrl Windows 7
+
+ Mongolian (Cyrillic) Mongolia 0x0450 mn-MN Release D
+
+ Mongolian (Traditional 0x7C50 mn-Mong Windows 7
+ Mongolian)
+
+ Mongolian (Traditional People's Republic of China 0x0850 mn-Mong- Release V
+ Mongolian) CN
+
+ Mongolian (Traditional Mongolia 0x0C50 mn-Mong- Windows 7
+ Mongolian) MN
+
+ Morisyen 0x1000 mfe Release 10
+
+ Morisyen Mauritius 0x1000 mfe-MU Release 10
+
+
+ 48 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Mundang 0x1000 mua Release 10
+
+ Mundang Cameroon 0x1000 mua-CM Release 10
+
+ N'ko 0x1000 nqo Release 8.1
+
+ N'ko Guinea 0x1000 nqo-GN Release 8.1
+
+ Nama 0x1000 naq Release 10
+
+ Nama Namibia 0x1000 naq-NA Release 10
+
+ Nepali 0x0061 ne Release 7
+
+ Nepali India 0x0861 ne-IN Release 8.1
+
+ Nepali Nepal 0x0461 ne-NP Release E2
+
+ Ngiemboon 0x1000 nnh Release 10
+
+ Ngiemboon Cameroon 0x1000 nnh-CM Release 10
+
+ Ngomba 0x1000 jgo Release 10
+
+ Ngomba Cameroon 0x1000 jgo-CM Release 10
+
+ Nheengatu 0x1000 yrl Release 11
+
+ Nheengatu (Latin) 0x1000 yrl-Latn Release 11
+
+ Nheengatu (Latin) Brazil 0x1000 yrl-Latn-BR Release 11
+
+ Nheengatu (Latin) Colombia 0x1000 yrl-Latn-CO Release 11
+
+ Nheengatu (Latin) Venezuela 0x1000 yrl-Latn-VE Release 11
+
+ Northern Luri Iraq 0x1000 lrc-IQ Release 10.1
+
+ Northern Luri Iran 0x1000 lrc-IR Release 10.1
+
+ North Ndebele 0x1000 nd Release 10
+
+ North Ndebele Zimbabwe 0x1000 nd-ZW Release 10
+
+ Norwegian (Bokmal) 0x0014 no Release 7
+
+ Norwegian (Bokmal) 0x7C14 nb Release 7
+
+ Norwegian (Bokmal) Norway 0x0414 nb-NO Release A
+
+ Norwegian (Nynorsk) 0x7814 nn Release 7
+
+ Norwegian (Nynorsk) Norway 0x0814 nn-NO Release A
+
+ Norwegian Bokmål Svalbard and Jan Mayen 0x1000 nb-SJ Release 10
+
+ Nuer 0x1000 nus Release 10
+
+ Nuer Sudan 0x1000 nus-SD Release 10
+
+ Nuer South Sudan 0x1000 nus-SS Release 10.1
+
+
+
+ 49 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Nyankole 0x1000 nyn Release 10
+
+ Nyankole Uganda 0x1000 nyn-UG Release 10
+
+ Occitan 0x0082 oc Release 7
+
+ Occitan France 0x0482 oc-FR Release V
+
+ Occitan Spain 0x1000 oc-ES Release 11
+
+ Odia 0x0048 or Release 7
+
+ Odia India 0x0448 or-IN Release V
+
+ Oromo 0x0072 om Release 8.1
+
+ Oromo Ethiopia 0x0472 om-ET Release 8.1
+
+ Oromo Kenya 0x1000 om-KE Release 10
+
+ Ossetian 0x1000 os Release 10
+
+ Ossetian Cyrillic, Georgia 0x1000 os-GE Release 10
+
+ Ossetian Cyrillic, Russia 0x1000 os-RU Release 10
+
+ Pashto 0x0063 ps Release 7
+
+ Pashto Afghanistan 0x0463 ps-AF Release E2
+
+ Pashto Pakistan 0x1000 ps-PK Release 10.5
+
+ Persian 0x0029 fa Release 7
+
+ Persian Afghanistan 0x1000 fa-AF Release 10
+
+ Persian Iran 0x0429 fa-IR Release B
+
+ Polish 0x0015 pl Release 7
+
+ Polish Poland 0x0415 pl-PL Release A
+
+ Portuguese 0x0016 pt Release 7
+
+ Portuguese Angola 0x1000 pt-AO Release 8.1
+
+ Portuguese Brazil 0x0416 pt-BR Release A
+
+ Portuguese Cabo Verde 0x1000 pt-CV Release 10
+
+ Portuguese Equatorial Guinea 0x1000 pt-GQ Release 10.2
+
+ Portuguese Guinea-Bissau 0x1000 pt-GW Release 10
+
+ Portuguese Luxembourg 0x1000 pt-LU Release 10.2
+
+ Portuguese Macao SAR 0x1000 pt-MO Release 10
+
+ Portuguese Mozambique 0x1000 pt-MZ Release 10
+
+ Portuguese Portugal 0x0816 pt-PT Release A
+
+
+
+ 50 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Portuguese São Tomé and Príncipe 0x1000 pt-ST Release 10
+
+ Portuguese Switzerland 0x1000 pt-CH Release 10.2
+
+ Portuguese Timor-Leste 0x1000 pt-TL Release 10
+
+ Prussian 0x1000 prg-001 Release 10.1
+
+ Pseudo Language Pseudo locale for east Asian/complex 0x05FE qps-ploca Release 7
+ script localization testing
+
+ Pseudo Language Pseudo locale used for localization 0x0501 qps-ploc Release 7
+ testing
+
+ Pseudo Language Pseudo locale used for localization 0x09FF qps-plocm Release 7
+ testing of mirrored locales
+
+ Punjabi 0x0046 pa Release 7
+
+ Punjabi 0x7C46 pa-Arab Release 8
+
+ Punjabi India 0x0446 pa-IN Release D
+
+ Punjabi Islamic Republic of Pakistan 0x0846 pa-Arab-PK Release 8
+
+ Quechua 0x006B quz Release 7
+
+ Quechua Bolivia 0x046B quz-BO Release E1
+
+ Quechua Ecuador 0x086B quz-EC Release E1
+
+ Quechua Peru 0x0C6B quz-PE Release E1
+
+ Rajasthani 0x1000 raj Release 11
+
+ Rajasthani 0x1000 raj-Deva Release 11
+ (Devanagari)
+
+ Rajasthani India 0x1000 raj-Deva-IN Release 11
+ (Devanagari)
+
+ Ripuarian 0x1000 ksh Release 10
+
+ Ripuarian Germany 0x1000 ksh-DE Release 10
+
+ Romanian 0x0018 ro Release 7
+
+ Romanian Moldova 0x0818 ro-MD Release 8.1
+
+ Romanian Romania 0x0418 ro-RO Release A
+
+ Romansh 0x0017 rm Release 7
+
+ Romansh Switzerland 0x0417 rm-CH Release E2
+
+ Rombo 0x1000 rof Release 10
+
+ Rombo Tanzania 0x1000 rof-TZ Release 10
+
+ Rundi 0x1000 rn Release 10
+
+ Rundi Burundi 0x1000 rn-BI Release 10
+
+
+ 51 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Russian 0x0019 ru Release 7
+
+ Russian Belarus 0x1000 ru-BY Release 10
+
+ Russian Kazakhstan 0x1000 ru-KZ Release 10
+
+ Russian Kyrgyzstan 0x1000 ru-KG Release 10
+
+ Russian Moldova 0x0819 ru-MD Release 10
+
+ Russian Russia 0x0419 ru-RU Release A
+
+ Russian Ukraine 0x1000 ru-UA Release 10
+
+ Rwa 0x1000 rwk Release 10
+
+ Rwa Tanzania 0x1000 rwk-TZ Release 10
+
+ Saho 0x1000 ssy Release 10
+
+ Saho Eritrea 0x1000 ssy-ER Release 10
+
+ Sakha 0x0085 sah Release 7
+
+ Sakha Russia 0x0485 sah-RU Release V
+
+ Samburu 0x1000 saq Release 10
+
+ Samburu Kenya 0x1000 saq-KE Release 10
+
+ Sami (Inari) 0x703B smn Windows 7
+
+ Sami (Inari) Finland 0x243B smn-FI Release E1
+
+ Sami (Lule) 0x7C3B smj Windows 7
+
+ Sami (Lule) Norway 0x103B smj-NO Release E1
+
+ Sami (Lule) Sweden 0x143B smj-SE Release E1
+
+ Sami (Northern) 0x003B se Release 7
+
+ Sami (Northern) Finland 0x0C3B se-FI Release E1
+
+ Sami (Northern) Norway 0x043B se-NO Release E1
+
+ Sami (Northern) Sweden 0x083B se-SE Release E1
+
+ Sami (Skolt) 0x743B sms Windows 7
+
+ Sami (Skolt) Finland 0x203B sms-FI Release E1
+
+ Sami (Southern) 0x783B sma Windows 7
+
+ Sami (Southern) Norway 0x183B sma-NO Release E1
+
+ Sami (Southern) Sweden 0x1C3B sma-SE Release E1
+
+ Sango 0x1000 sg Release 10
+
+ Sango Central African Republic 0x1000 sg-CF Release 10
+
+
+
+ 52 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Sangu 0x1000 sbp Release 10
+
+ Sangu Tanzania 0x1000 sbp-TZ Release 10
+
+ Sanskrit 0x004F sa Release 7
+
+ Sanskrit India 0x044F sa-IN Release C
+
+ Sardinian 0x1000 sc Release 11
+
+ Sardinian (Latin) 0x1000 sc-Latn Release 11
+
+ Sardinian (Latin) Italy 0x1000 sc-Latn-IT Release 11
+
+ Scottish Gaelic 0x0091 gd Windows 7
+
+ Scottish Gaelic United Kingdom 0x0491 gd-GB Release 7
+
+ Sena 0x1000 seh Release 10
+
+ Sena Mozambique 0x1000 seh-MZ Release 10
+
+ Serbian (Cyrillic) 0x6C1A sr-Cyrl Windows 7
+
+ Serbian (Cyrillic) Bosnia and Herzegovina 0x1C1A sr-Cyrl-BA Release E1
+
+ Serbian (Cyrillic) Montenegro 0x301A sr-Cyrl-ME Release 7
+
+ Serbian (Cyrillic) Serbia 0x281A sr-Cyrl-RS Release 7
+
+ Serbian (Cyrillic) Serbia and Montenegro (Former) 0x0C1A sr-Cyrl-CS Release B
+
+ Serbian (Latin) 0x701A sr-Latn Windows 7
+
+ Serbian (Latin) 0x7C1A sr Release 7
+
+ Serbian (Latin) Bosnia and Herzegovina 0x181A sr-Latn-BA Release E1
+
+ Serbian (Latin) Montenegro 0x2c1A sr-Latn-ME Release 7
+
+ Serbian (Latin) Serbia 0x241A sr-Latn-RS Release 7
+
+ Serbian (Latin) Serbia and Montenegro (Former) 0x081A sr-Latn-CS Release B
+
+ Sesotho sa Leboa 0x006C nso Release 7
+
+ Sesotho sa Leboa South Africa 0x046C nso-ZA Release E1
+
+ Setswana 0x0032 tn Release 7
+
+ Setswana Botswana 0x0832 tn-BW Release 8
+
+ Setswana South Africa 0x0432 tn-ZA Release E1
+
+ Shambala 0x1000 ksb Release 10
+
+ Shambala Tanzania 0x1000 ksb-TZ Release 10
+
+ Shona 0x1000 sn Release 8.1
+
+ Shona Latin 0x1000 sn-Latn Release 8.1
+
+
+
+ 53 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Shona Zimbabwe 0x1000 sn-Latn-ZW Release 8.1
+
+ Sindhi 0x0059 sd Release 8
+
+ Sindhi 0x7C59 sd-Arab Release 8
+
+ Sindhi Islamic Republic of Pakistan 0x0859 sd-Arab-PK Release 8
+
+ Sinhala 0x005B si Release 7
+
+ Sinhala Sri Lanka 0x045B si-LK Release V
+
+ Slovak 0x001B sk Release 7
+
+ Slovak Slovakia 0x041B sk-SK Release A
+
+ Slovenian 0x0024 sl Release 7
+
+ Slovenian Slovenia 0x0424 sl-SI Release A
+
+ Soga 0x1000 xog Release 10
+
+ Soga Uganda 0x1000 xog-UG Release 10
+
+ Somali 0x0077 so Release 8.1
+
+ Somali Djibouti 0x1000 so-DJ Release 10
+
+ Somali Ethiopia 0x1000 so-ET Release 10
+
+ Somali Kenya 0x1000 so-KE Release 10
+
+ Somali Somalia 0x0477 so-SO Release 8.1
+
+ Sotho 0x0030 st Release 8.1
+
+ Sotho South Africa 0x0430 st-ZA Release 8.1
+
+ South Ndebele 0x1000 nr Release 10
+
+ South Ndebele South Africa 0x1000 nr-ZA Release 10
+
+ Southern Sotho Lesotho 0x1000 st-LS Release 10
+
+ Spanish 0x000A es Release 7
+
+ Spanish Argentina 0x2C0A es-AR Release B
+
+ Spanish Belize 0x1000 es-BZ Release 10.3
+
+ Spanish Bolivarian Republic of Venezuela 0x200A es-VE Release B
+
+ Spanish Bolivia 0x400A es-BO Release B
+
+ Spanish Brazil 0x1000 es-BR Release 10.2
+
+ Spanish Chile 0x340A es-CL Release B
+
+ Spanish Colombia 0x240A es-CO Release B
+
+ Spanish Costa Rica 0x140A es-CR Release B
+
+
+
+ 54 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Spanish Cuba 0x5c0A es-CU Release 10
+
+ Spanish Dominican Republic 0x1c0A es-DO Release B
+
+ Spanish Ecuador 0x300A es-EC Release B
+
+ Spanish El Salvador 0x440A es-SV Release B
+
+ Spanish Equatorial Guinea 0x1000 es-GQ Release 10
+
+ Spanish Guatemala 0x100A es-GT Release B
+
+ Spanish Honduras 0x480A es-HN Release B
+
+ Spanish Latin America 0x580A es-419 Release 8.1
+
+ Spanish Mexico 0x080A es-MX Release A
+
+ Spanish Nicaragua 0x4C0A es-NI Release B
+
+ Spanish Panama 0x180A es-PA Release B
+
+ Spanish Paraguay 0x3C0A es-PY Release B
+
+ Spanish Peru 0x280A es-PE Release B
+
+ Spanish Philippines 0x1000 es-PH Release 10
+
+ Spanish Puerto Rico 0x500A es-PR Release B
+
+ Spanish Spain 0x040A es-ES_tradnl Release A
+
+ Spanish Spain 0x0c0A es-ES Release A
+
+ Spanish United States 0x540A es-US Release V
+
+ Spanish Uruguay 0x380A es-UY Release B
+
+ Standard Moroccan 0x1000 zgh Release 8.1
+ Tamazight
+
+ Standard Moroccan Morocco 0x1000 zgh-Tfng-MA Release 8.1
+ Tamazight
+
+ Standard Moroccan Tifinagh 0x1000 zgh-Tfng Release 8.1
+ Tamazight
+
+ Swati 0x1000 ss Release 10
+
+ Swati South Africa 0x1000 ss-ZA Release 10
+
+ Swati Swaziland 0x1000 ss-SZ Release 10
+
+ Swedish 0x001D sv Release 7
+
+ Swedish Åland Islands 0x1000 sv-AX Release 10
+
+ Swedish Finland 0x081D sv-FI Release B
+
+ Swedish Sweden 0x041D sv-SE Release A
+
+ Syriac 0x005A syr Release 7
+
+
+ 55 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Syriac Syria 0x045A syr-SY Release D
+
+ Tachelhit 0x1000 shi Release 10
+
+ Tachelhit Tifinagh 0x1000 shi-Tfng Release 10
+
+ Tachelhit Tifinagh, Morocco 0x1000 shi-Tfng-MA Release 10
+
+ Tachelhit (Latin) 0x1000 shi-Latn Release 10
+
+ Tachelhit (Latin) Morocco 0x1000 shi-Latn-MA Release 10
+
+ Taita 0x1000 dav Release 10
+
+ Taita Kenya 0x1000 dav-KE Release 10
+
+ Tajik (Cyrillic) 0x0028 tg Release 7
+
+ Tajik (Cyrillic) 0x7C28 tg-Cyrl Windows 7
+
+ Tajik (Cyrillic) Tajikistan 0x0428 tg-Cyrl-TJ Release V
+
+ Tamazight (Latin) 0x005F tzm Release 7
+
+ Tamazight (Latin) 0x7C5F tzm-Latn Windows 7
+
+ Tamazight (Latin) Algeria 0x085F tzm-Latn-DZ Release V
+
+ Tamil 0x0049 ta Release 7
+
+ Tamil India 0x0449 ta-IN Release C
+
+ Tamil Malaysia 0x1000 ta-MY Release 10
+
+ Tamil Singapore 0x1000 ta-SG Release 10
+
+ Tamil Sri Lanka 0x0849 ta-LK Release 8
+
+ Tasawaq 0x1000 twq Release 10
+
+ Tasawaq Niger 0x1000 twq-NE Release 10
+
+ Tatar 0x0044 tt Release 7
+
+ Tatar Russia 0x0444 tt-RU Release D
+
+ Telugu 0x004A te Release 7
+
+ Telugu India 0x044A te-IN Release D
+
+ Teso 0x1000 teo Release 10
+
+ Teso Kenya 0x1000 teo-KE Release 10
+
+ Teso Uganda 0x1000 teo-UG Release 10
+
+ Thai 0x001E th Release 7
+
+ Thai Thailand 0x041E th-TH Release B
+
+ Tibetan 0x0051 bo Release 7
+
+
+
+ 56 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Tibetan India 0x1000 bo-IN Release 10
+
+ Tibetan People's Republic of China 0x0451 bo-CN Release V
+
+ Tigre 0x1000 tig Release 10
+
+ Tigre Eritrea 0x1000 tig-ER Release 10
+
+ Tigrinya 0x0073 ti Release 8
+
+ Tigrinya Eritrea 0x0873 ti-ER Release 8
+
+ Tigrinya Ethiopia 0x0473 ti-ET Release 8
+
+ Tongan 0x1000 to Release 10
+
+ Tongan Tonga 0x1000 to-TO Release 10
+
+ Tsonga 0x0031 ts Release 8.1
+
+ Tsonga South Africa 0x0431 ts-ZA Release 8.1
+
+ Turkish 0x001F tr Release 7
+
+ Turkish Cyprus 0x1000 tr-CY Release 10
+
+ Turkish Turkey 0x041F tr-TR Release A
+
+ Turkmen 0x0042 tk Release 7
+
+ Turkmen Turkmenistan 0x0442 tk-TM Release V
+
+ Ukrainian 0x0022 uk Release 7
+
+ Ukrainian Ukraine 0x0422 uk-UA Release B
+
+ Upper Sorbian 0x002E hsb Release 7
+
+ Upper Sorbian Germany 0x042E hsb-DE Release V
+
+ Urdu 0x0020 ur Release 7
+
+ Urdu India 0x0820 ur-IN Release 8.1
+
+ Urdu Islamic Republic of Pakistan 0x0420 ur-PK Release C
+
+ Uyghur 0x0080 ug Release 7
+
+ Uyghur People's Republic of China 0x0480 ug-CN Release V
+
+ Uzbek Perso-Arabic 0x1000 uz-Arab Release 10
+
+ Uzbek Perso-Arabic, Afghanistan 0x1000 uz-Arab-AF Release 10
+
+ Uzbek (Cyrillic) 0x7843 uz-Cyrl Windows 7
+
+ Uzbek (Cyrillic) Uzbekistan 0x0843 uz-Cyrl-UZ Release C
+
+ Uzbek (Latin) 0x0043 uz Release 7
+
+ Uzbek (Latin) 0x7C43 uz-Latn Windows 7
+
+
+
+ 57 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Uzbek (Latin) Uzbekistan 0x0443 uz-Latn-UZ Release C
+
+ Vai 0x1000 vai Release 10
+
+ Vai 0x1000 vai-Vaii Release 10
+
+ Vai Liberia 0x1000 vai-Vaii-LR Release 10
+
+ Vai (Latin) Liberia 0x1000 vai-Latn-LR Release 10
+
+ Vai (Latin) 0x1000 vai-Latn Release 10
+
+ Valencian Spain 0x0803 ca-ES- Release 8
+ valencia
+
+ Venda 0x0033 ve Release 10
+
+ Venda South Africa 0x0433 ve-ZA Release 10
+
+ Vietnamese 0x002A vi Release 7
+
+ Vietnamese Vietnam 0x042A vi-VN Release B
+
+ Volapük 0x1000 vo Release 10
+
+ Volapük World 0x1000 vo-001 Release 10
+
+ Vunjo 0x1000 vun Release 10
+
+ Vunjo Tanzania 0x1000 vun-TZ Release 10
+
+ Walser 0x1000 wae Release 10
+
+ Walser Switzerland 0x1000 wae-CH Release 10
+
+ Welsh 0x0052 cy Release 7
+
+ Welsh United Kingdom 0x0452 cy-GB Release E1
+
+ Wolaytta 0x1000 wal Release 10
+
+ Wolaytta Ethiopia 0x1000 wal-ET Release 10
+
+ Wolof 0x0088 wo Release 7
+
+ Wolof Senegal 0x0488 wo-SN Release V
+
+ Xhosa 0x0034 xh Release 7
+
+ Xhosa South Africa 0x0434 xh-ZA Release E1
+
+ Yangben 0x1000 yav Release 10
+
+ Yangben Cameroon 0x1000 yav-CM Release 10
+
+ Yi 0x0078 ii Release 7
+
+ Yi People's Republic of China 0x0478 ii-CN Release V
+
+ Yiddish World 0x043D yi-001 Release 10
+
+ Yoruba 0x006A yo Release 7
+
+
+ 58 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ Language Language Supported
+ Language Location (or type) ID tag version
+
+ Yoruba Benin 0x1000 yo-BJ Release 10
+
+ Yoruba Nigeria 0x046A yo-NG Release V
+
+ Zarma 0x1000 dje Release 10
+
+ Zarma Niger 0x1000 dje-NE Release 10
+
+ Zulu 0x0035 zu Release 7
+
+ Zulu South Africa 0x0435 zu-ZA Release E1
+
+
+
+
+<9> Section 2.2: Supported only on Windows 7.
+
+<10> Section 2.2: Supported only on Windows 7.
+
+<11> Section 2.2: Supported only on Windows 7.
+
+<12> Section 2.2: Not supported in client releases earlier than Windows 10 or server releases earlier
+than Windows Server 2016.
+
+<13> Section 2.2: Not supported in client releases earlier than Windows 10 or server releases earlier
+than Windows Server 2016.
+
+<14> Section 2.2.1: The temporary Locale Names without LCID assignments are not supported in
+versions before Windows Vista and Windows Server 2008 operating system with Service Pack 2 (SP2).
+
+<15> Section 2.2.1: Not supported in versions before Windows Vista and Windows Server 2008.
+
+<16> Section 2.2.1: The Transient LCIDs (0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400,
+0x3800, 0x3C00, 0x4000, 0x4400, 0x4800, and 0x4C00) were introduced in Windows 8 operating
+system and Windows Server 2012 operating system and fail in all prior versions.
+
+<17> Section 2.2.1: Not supported in versions before Windows Vista and Windows Server 2008.
+
+
+
+
+ 59 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ 6 Change Tracking
+This section identifies changes that were made to this document since the last release. Changes are
+classified as Major, Minor, or None.
+
+The revision class Major means that the technical content in the document was significantly revised.
+Major changes affect protocol interoperability or implementation. Examples of major changes are:
+
+ A document revision that incorporates changes to interoperability requirements.
+ A document revision that captures changes to protocol functionality.
+
+The revision class Minor means that the meaning of the technical content was clarified. Minor changes
+do not affect protocol interoperability or implementation. Examples of minor changes are updates to
+clarify ambiguity at the sentence, paragraph, or table level.
+
+The revision class None means that no new technical changes were introduced. Minor editorial and
+formatting changes may have been made, but the relevant technical content is identical to the last
+released version.
+
+The changes made to this document are listed in the following table. For more information, please
+contact dochelp@microsoft.com.
+
+ Revision
+ Section Description
+ class
+
+ 11352 : Added four unassigned locales temporarily assigned to
+ 2.2 LCID Structure Major
+ 0x3000.
+
+ Updated for Windows 11 24H2 and Windows Server 2025.
+ 2.2 LCID Structure Major
+ Updated the list of neutrals and locales.
+
+ 2.2.1 Locale Names 11352 : Added four unassigned locales temporarily assigned to
+ Major
+ without LCIDs 0x3000.
+
+ 5 Appendix A: Product
+ Added Windows Server 2025 to the product applicability list. Major
+ Behavior
+
+
+
+
+ 60 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ 7 Index
+.
+ T
+.NET - LCIDs as culture identifiers 8
+ Tracking changes 60
+A
+ V
+Applicability 7
+ Vendor-extensible fields 7
+C Versioning 7
+
+Change tracking 60
+Culture identifiers 8
+
+E
+
+Examples 27
+Examples - LCID values 27
+
+F
+
+Fields - vendor-extensible 7
+
+G
+
+Glossary 5
+
+I
+
+Implementer - security considerations 28
+Informative references 6
+Introduction 5
+
+L
+
+LCID packet 8
+Localization 7
+
+N
+
+Normative references 6
+
+O
+
+Overview (synopsis) 6
+
+P
+
+Product behavior 29
+
+R
+
+References 6
+ informative 6
+ normative 6
+Relationship to protocols and other structures 7
+
+S
+
+Security 28
+Security - implementer considerations 28
+
+
+ 61 / 61
+[MS-LCID] - v20240423
+Windows Language Code Identifier (LCID) Reference
+Copyright © 2024 Microsoft Corporation
+Release: April 23, 2024
+ \ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 35a63ad..73c6b8f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-# CMAkeLists.txt - Main build script for sbc-harness
+# CMakeLists.txt - Main build script for sbc-harness project
#
# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-Licence-Identifier: AGPL-3.0-or-later
@@ -12,23 +12,15 @@ project(sbc_harness)
pico_sdk_init()
-add_executable(sbc_harness)
-target_sources(sbc_harness PUBLIC
- main.c
- coroutine.c
- usb_common.c
- usb_keyboard.c
+add_custom_target(generate
+ COMMENT Create generated files that are included in the source distribution
)
-target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_LIST_DIR}) # So TinyUSB can find tusb_config.h
-target_link_libraries(sbc_harness
- pico_stdlib
- pico_unique_id
- tinyusb_device
- tinyusb_board
-)
-pico_enable_stdio_usb(sbc_harness 0)
-pico_enable_stdio_uart(sbc_harness 1)
-pico_enable_stdio_semihosting(sbc_harness 0)
-pico_enable_stdio_rtt(sbc_harness 0)
-pico_add_extra_outputs(sbc_harness) # create map/bin/hex/uf2 file in addition to ELF.
-pico_set_program_url(sbc_harness "https://git.lukeshu.com/sbc-harness")
+
+add_subdirectory(libcr)
+add_subdirectory(libcr_ipc)
+add_subdirectory(libusb)
+add_subdirectory(libnetio)
+add_subdirectory(lib9p)
+
+add_subdirectory(cmd/sbc_harness)
+add_subdirectory(cmd/srv9p)
diff --git a/HACKING.md b/HACKING.md
new file mode 100644
index 0000000..1492820
--- /dev/null
+++ b/HACKING.md
@@ -0,0 +1,10 @@
+Source layout
+
+ - cmd/sbc_harness
+ - cmd/srv9p
+ - libcr - A simple coroutine (cooperative multitasking) library
+ - libcr_ipc - IPC primatives for coroutines built on top of libcr
+ - libnetio - TODO
+ - lib9p - A simple 9P protocol server library
+ - libusb - TODO
+
diff --git a/PLAN.md b/PLAN.md
index da65817..a469acb 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -12,3 +12,5 @@
1. [ ] PicoDVI hello-world
2. [ ] "PiciDVI" to network
3. [ ] reverse the flow of PicoDVI
+
+https://hackaday.com/2022/08/26/bit-banged-ethernet-on-the-raspberry-pi-pico/
diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt
new file mode 100644
index 0000000..34f6360
--- /dev/null
+++ b/cmd/sbc_harness/CMakeLists.txt
@@ -0,0 +1,23 @@
+# cmd/sbc_harness/CMakeLists.txt - Build script for main sbc_harness.uf2 firmware file
+#
+# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-Licence-Identifier: AGPL-3.0-or-later
+
+add_executable(sbc_harness
+ main.c
+ usb_keyboard.c
+)
+target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
+target_link_libraries(sbc_harness
+ pico_stdlib
+ pico_unique_id
+ tinyusb_device
+ tinyusb_board
+ libusb
+)
+pico_enable_stdio_usb(sbc_harness 0)
+pico_enable_stdio_uart(sbc_harness 1)
+pico_enable_stdio_semihosting(sbc_harness 0)
+pico_enable_stdio_rtt(sbc_harness 0)
+pico_add_extra_outputs(sbc_harness) # create .map/.bin/.hex/.uf2 files in addition to .elf
+pico_set_program_url(sbc_harness "https://git.lukeshu.com/sbc-harness")
diff --git a/config.h b/cmd/sbc_harness/config/config.h
index 37bfcbe..0f0385b 100644
--- a/config.h
+++ b/cmd/sbc_harness/config/config.h
@@ -1,4 +1,4 @@
-/* config.h - Compile-time configuration for sbc-harness
+/* config.h - Compile-time configuration for sbc_harness
*
* Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-Licence-Identifier: AGPL-3.0-or-later
@@ -28,10 +28,6 @@
/*static_assert((CONFIG_COROUTINE_NUM * CONFIG_COROUTINE_DEFAULT_STACK_SIZE) < (264 * 1024)); */
#endif
-#ifdef USE_CONFIG_TUSB
-# include "tusb_config.h"
-#endif
-
#ifdef USE_CONFIG_9P
# define CONFIG_9P_PORT 564
/**
diff --git a/libusb/tusb_config.h b/cmd/sbc_harness/config/tusb_config.h
index cb1ca3b..cb1ca3b 100644
--- a/libusb/tusb_config.h
+++ b/cmd/sbc_harness/config/tusb_config.h
diff --git a/cmd/harness/main.c b/cmd/sbc_harness/main.c
index 1fd9f8c..1fd9f8c 100644
--- a/cmd/harness/main.c
+++ b/cmd/sbc_harness/main.c
diff --git a/cmd/harness/usb_keyboard.c b/cmd/sbc_harness/usb_keyboard.c
index 1989b35..1989b35 100644
--- a/cmd/harness/usb_keyboard.c
+++ b/cmd/sbc_harness/usb_keyboard.c
diff --git a/cmd/harness/usb_keyboard.h b/cmd/sbc_harness/usb_keyboard.h
index 6b65360..6b65360 100644
--- a/cmd/harness/usb_keyboard.h
+++ b/cmd/sbc_harness/usb_keyboard.h
diff --git a/cmd/srv9p/CMakeLists.txt b/cmd/srv9p/CMakeLists.txt
new file mode 100644
index 0000000..3db8795
--- /dev/null
+++ b/cmd/srv9p/CMakeLists.txt
@@ -0,0 +1,15 @@
+# cmd/srv9p/CMakeLists.txt - Build script for srv9p test/dev executable
+#
+# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-Licence-Identifier: AGPL-3.0-or-later
+
+add_executable(srv9p
+ main.c
+)
+target_include_directories(srv9p PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
+target_link_libraries(srv9p
+ libcr
+ libcr_ipc
+ libnetio
+ lib9p
+)
diff --git a/cmd/srv9p/config/config.h b/cmd/srv9p/config/config.h
new file mode 120000
index 0000000..2edbd7b
--- /dev/null
+++ b/cmd/srv9p/config/config.h
@@ -0,0 +1 @@
+../../sbc_harness/config/config.h \ No newline at end of file
diff --git a/lib9p/.editorconfig b/lib9p/.editorconfig
index 3f04564..5c79099 100644
--- a/lib9p/.editorconfig
+++ b/lib9p/.editorconfig
@@ -1,3 +1,3 @@
-[{defs.gen,linux-errno.h.gen}]
+[{types.gen,linux-errno.h.gen}]
indent_style = space
indent_size = 4
diff --git a/lib9p/.gitignore b/lib9p/.gitignore
deleted file mode 100644
index 667e81c..0000000
--- a/lib9p/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/defs-*
-/linux-errno.h
diff --git a/lib9p/9P2000.e.txt b/lib9p/9P2000.e.txt
index 22f056e..e60bce0 100644
--- a/lib9p/9P2000.e.txt
+++ b/lib9p/9P2000.e.txt
@@ -8,9 +8,11 @@
# https://github.com/cloudozer/ling/blob/master/doc/9p2000e.md
version "9P2000.e"
+from 9P2000.txt import *
+
150/Tsession = "key[8]"
151/Rsession = ""
152/Tsread = "fid[4] nwname[2] nwname*(wname[s])"
153/Rsread = "data[d]"
-154/Tswrite = "Tswrite tag[2] fid[4] nwname[2] nwname*(wname[s]) data[d]"
+154/Tswrite = "fid[4] nwname[2] nwname*(wname[s]) data[d]"
155/Rswrite = "count[4]"
diff --git a/lib9p/9P2000.u.txt b/lib9p/9P2000.u.txt
index 60d2b11..1fa71fb 100644
--- a/lib9p/9P2000.u.txt
+++ b/lib9p/9P2000.u.txt
@@ -18,3 +18,28 @@ stat += "file_extension[s]"
Tauth += "n_uname[4]"
Rerror += "errno[4]"
+
+# # qid.types
+# QTDIR = 1<<7
+# QTAPPEND = 1<<6
+# QTEXCL = 1<<5
+# QTMOUNT = 1<<4 # been around forever, but undocumented?
+# QTAUTH = 1<<3
+# QTTMP = 1<<2 # added to Plan 9 2003-12
+# QTSYMLINK = 1<<1 # .u
+# QTFILE = 1<<0
+#
+# DMDIR = 1<<31
+# DMAPPEND = 1<<30
+# DMEXCL = 1<<29
+# DMMOUNT = 1<<28
+# DMAUTH = 1<<27
+# DMTMP = 1<<26
+# # = 1<<25
+# # = 1<<24
+# DMDEVICE = 1<<23 # .u
+# # = 1<<22
+# DMNAMEDPIPE = 1<<21 # .u
+# DMSOCKET = 1<<20 # .u
+# DMSETUID = 1<<19 # .u
+# DMSETGID = 1<<18 # .u
diff --git a/lib9p/defs.c b/lib9p/9p.c
index 886a0c1..64b09a6 100644
--- a/lib9p/defs.c
+++ b/lib9p/9p.c
@@ -1,4 +1,4 @@
-/* 9p/defs.c - TODO
+/* lib9p/9p.c - Base 9P protocol utilities for both clients and servers
*
* Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-Licence-Identifier: AGPL-3.0-or-later
@@ -9,23 +9,28 @@
#include <stdio.h> /* for vsnprintf() */
#include <string.h> /* for strncpy() */
-#include "9p/defs.h"
-#include "9p/linux-errno.h"
-#include "9p/internal.h"
+#include <lib9p/9p.h>
-static struct version *versions[_P9_VER_CNT] = {
- [P9_VER_9P2000] = &version_9P2000,
- /* [P9_VER_9P2000u] = &version_9P2000u, */
-};
+#include "internal.h"
-int p9_error(struct p9_ctx *ctx, uint32_t linux_errno, char const *msg) {
+enum lib9p_version lib9p_ctx_version(lib9p_ctx *ctx) {
+ assert(ctx);
+ return ctx->version;
+}
+
+uint32_t lib9p_ctx_max_msg_size(lib9p_ctx *ctx) {
+ assert(ctx);
+ return ctx->max_msg_size;
+}
+
+int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg) {
strncpy(ctx->err_msg, msg, sizeof(ctx->err_msg));
ctx->err_msg[sizeof(ctx->err_msg)-1] = '\0';
ctx->err_num = linux_errno;
return -1;
}
-int p9_errorf(struct p9_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) {
+int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) {
int n;
va_list args;
@@ -40,25 +45,25 @@ int p9_errorf(struct p9_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) {
return -1;
}
-size_t p9_unmarshal_size(struct p9_ctx *ctx, uint8_t *net_bytes) {
+size_t lib9p_unmarshal_size(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
/* Header */
uint32_t net_len = decode_u32le(net_bytes);
if (net_len < 7)
- return p9_error(ctx, LINUX_EBADMSG, "message is too short");
+ return lib9p_error(ctx, LINUX_EBADMSG, "message is too short");
uint8_t typ = net_bytes[4];
uint32_t net_offset = 7;
/* Body */
if (!versions[ctx->version]->msgs[typ].unmarshal_extrasize)
- return p9_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %"PRIu8, typ);
+ return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %"PRIu8, typ);
size_t host_size = versions[ctx->version]->msgs[typ].unmarshal_basesize;
if (versions[ctx->version]->msgs[typ].unmarshal_extrasize(net_len, net_bytes, &net_offset, &host_size))
- return p9_error(ctx, LINUX_EBADMSG, "message is too short for content");
+ return lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content");
return host_size;
}
-uint8_t p9_unmarshal(struct p9_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, void *out_body) {
+uint8_t lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, void *out_body) {
/* Header */
uint8_t typ = net_bytes[4];
*out_tag = decode_u16le(&net_bytes[5]);
@@ -67,12 +72,12 @@ uint8_t p9_unmarshal(struct p9_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag,
/* Body */
void *host_extra = out_body + versions[ctx->version]->msgs[typ].unmarshal_basesize;
if (versions[ctx->version]->msgs[typ].unmarshal(net_bytes, &net_offset, &host_extra, out_body))
- return p9_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8");
+ return lib9p_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8");
return typ;
}
-uint32_t _p9_marshal(struct p9_ctx *ctx, uint8_t typ, uint16_t msgid, void *body, uint8_t *out_bytes) {
+uint32_t lib9p_marshal(struct lib9p_ctx *ctx, uint8_t typ, uint16_t msgid, void *body, uint8_t *out_bytes) {
/* Header */
out_bytes[4] = typ;
encode_u16le(msgid, &out_bytes[5]);
diff --git a/lib9p/9p.h b/lib9p/9p.h
deleted file mode 100644
index 63fbd04..0000000
--- a/lib9p/9p.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* 9p/9p.h - TODO
- *
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-Licence-Identifier: AGPL-3.0-or-later
- */
-
-#include "9p/linux-errno.h"
-#include "9p/defs.h"
-#include "9p/defs-9P2000.h"
-/*#include "9p/defs-9P2000.u.h"*/
-
-#define P9_TYPECODE_FOR_CTYPE(msg) _Generic((in_msg) \
- _P9_TYPECODE_FOR_CTYPE_9P2000(msg) \
- /* _P9_TYPECODE_FOR_CTYPE_9P2000u(msg) */ \
- )
diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt
new file mode 100644
index 0000000..0faa109
--- /dev/null
+++ b/lib9p/CMakeLists.txt
@@ -0,0 +1,34 @@
+# libcr/CMakeLists.txt - TODO
+#
+# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-Licence-Identifier: AGPL-3.0-or-later
+
+add_library(lib9p INTERFACE)
+target_sources(lib9p INTERFACE
+ types.c
+ 9p.c
+ srv.c
+)
+target_include_directories(lib9p SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+add_custom_command(
+ OUTPUT ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt
+ DEPENDS ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt.gen
+ COMMAND ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt.gen
+)
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/linux-errno.h
+ DEPENDS include/lib9p/linux-errno.h.gen ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/linux-errno.h.gen ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt >${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/linux-errno.h
+)
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/types.c ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/_types.h
+ DEPENDS types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt
+)
+add_dependencies(generate
+ ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt
+ ${CMAKE_CURRENT_SOURCE_DIR}/linux-errno.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/types.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/_types.h
+)
diff --git a/lib9p/defs.gen b/lib9p/defs.gen
deleted file mode 100755
index 1a8dc69..0000000
--- a/lib9p/defs.gen
+++ /dev/null
@@ -1,456 +0,0 @@
-#!/usr/bin/env python
-# 9p/defs.gen - Generate C marshalers/unmarshalers for a .txt file
-# defining a 9P protocol variant.
-#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-Licence-Identifier: AGPL-3.0-or-later
-
-import enum
-import os.path
-import re
-
-PROGRAM = "./9p/defs.gen"
-
-# Parse the *.txt ##############################################################
-
-
-class Atom(enum.Enum):
- u8 = 1
- u16 = 2
- u32 = 4
- u64 = 8
-
- @property
- def name(self) -> str:
- return str(self.value)
-
- @property
- def static_size(self) -> int:
- return self.value
-
-
-# `msgid/structname = "member1 member2..."`
-# `structname = "member1 member2..."`
-# `structname += "member1 member2..."`
-class Struct:
- msgid: int | None = None
- name: str
- members: list["Member"]
-
- @property
- def static_size(self) -> int | None:
- size = 0
- for member in self.members:
- msize = member.static_size
- if msize is None:
- return None
- size += msize
- return size
-
-
-# `cnt*(name[typ])`
-# the `cnt*(...)` wrapper is optional
-class Member:
- cnt: str | None = None
- name: str
- typ: Atom | Struct
-
- @property
- def static_size(self) -> int | None:
- if self.cnt:
- return None
- return self.typ.static_size
-
-
-re_membername = "(?:[a-zA-Z_][a-zA-Z_0-9]*)"
-re_memberspec = (
- f"(?:(?P<cnt>{re_membername})\\*\\()?(?P<name>{re_membername})\\[(?P<typ>.*)\\]\\)?"
-)
-
-
-def parse_members(
- env: dict[str, Atom | Struct], existing: list[Member], specs: str
-) -> list[Member]:
- ret = existing
- for spec in specs.split():
- m = re.fullmatch(re_memberspec, spec)
- if not m:
- raise SyntaxError(f"invalid member spec {repr(spec)}")
-
- member = Member()
-
- member.name = m.group("name")
- if any(x.name == member.name for x in ret):
- raise ValueError(f"duplicate member name {repr(member.name)}")
-
- if m.group("typ") not in env:
- raise NameError(f"Unknown type {repr(m.group(2))}")
- member.typ = env[m.group("typ")]
-
- if cnt := m.group("cnt"):
- if len(ret) == 0 or ret[-1].name != cnt:
- raise ValueError(f"list count must be previous item: {repr(cnt)}")
- if not isinstance(ret[-1].typ, Atom):
- raise ValueError(f"list count must be an integer type: {repr(cnt)}")
- member.cnt = cnt
-
- ret += [member]
- return ret
-
-
-re_version = r'version\s+"(?P<version>[^"]+)"'
-re_structspec = (
- r'(?:(?P<msgid>[0-9]+)/)?(?P<name>\S+)\s*(?P<op>\+?=)\s*"(?P<members>[^"]*)"'
-)
-re_structspec_cont = r'"(?P<members>[^"]*)"'
-
-
-def parse_file(filename: str) -> tuple[str, list[Struct]]:
- version: str | None = None
- env: dict[str, Atom | Struct] = {
- "1": Atom.u8,
- "2": Atom.u16,
- "4": Atom.u32,
- "8": Atom.u64,
- }
- with open(filename, "r") as fh:
- prev: Struct | None = None
- for line in fh:
- line = line.split("#", 1)[0].strip()
- if not line:
- continue
- if m := re.fullmatch(re_version, line):
- if version:
- raise SyntaxError("must have exactly 1 version line")
- version = m.group("version")
- elif m := re.fullmatch(re_structspec, line):
- if m.group("op") == "+=" and m.group("msgid"):
- raise SyntaxError("cannot += to a message that is not yet defined")
- match m.group("op"):
- case "=":
- struct = Struct()
- if m.group("msgid"):
- struct.msgid = int(m.group("msgid"))
- struct.name = m.group("name")
- struct.members = parse_members(env, [], m.group("members"))
- env[struct.name] = struct
- prev = struct
- case "+=":
- if m.group("name") not in env:
- raise NameError(f"Unknown type {repr(m.group('name'))}")
- _struct = env[m.group("name")]
- if not isinstance(_struct, Struct):
- raise NameError(
- f"Type {repr(m.group('name'))} is not a struct"
- )
- struct = _struct
- struct.members = parse_members(
- env, struct.members, m.group("members")
- )
- prev = struct
- elif m := re.fullmatch(re_structspec_cont, line):
- if not prev:
- raise SyntaxError("continuation line must come after a struct line")
- prev.members = parse_members(env, prev.members, m.group("members"))
- else:
- raise SyntaxError(f"invalid line {repr(line)}")
- if not version:
- raise SyntaxError("must have exactly 1 version line")
- structs = [x for x in env.values() if isinstance(x, Struct)]
- return version, structs
-
-
-# Generate C ###################################################################
-
-
-def c_typename(idprefix: str, typ: Atom | Struct) -> str:
- match typ:
- case Atom():
- return f"uint{typ.value*8}_t"
- case Struct():
- if typ.msgid is not None:
- return f"struct {idprefix}msg_{typ.name}"
- return f"struct {idprefix}{typ.name}"
- case _:
- raise ValueError(f"not a type: {typ.__class__.__name__}")
-
-
-def gen_h(txtname: str, idprefix: str, structs: list[Struct]) -> str:
- guard = (
- f"_{txtname.replace('.txt', '.h').upper().replace('/', '_').replace('.', '_')}_"
- )
- ret = f"""/* Generated by `{PROGRAM} {txtname}`. DO NOT EDIT! */
-
-#ifndef {guard}
-#define {guard}
-
-#define {idprefix.upper()}MIN_MSGLEN 7
-"""
- ret += """
-/* non-message structs ********************************************************/
-
-"""
- for struct in structs:
- if struct.msgid is not None:
- continue
- ret += c_typename(idprefix, struct) + " {\n"
- typewidth = max(
- len(c_typename(idprefix, member.typ)) for member in struct.members
- )
- for member in struct.members:
- ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n"
- ret += "};\n"
-
- ret += """
-/* message types **************************************************************/
-
-"""
- ret += f"enum {idprefix}msg_type {{ /* uint8_t */\n"
- namewidth = max(len(msg.name) for msg in structs if msg.msgid is not None)
- for msg in structs:
- if msg.msgid is None:
- continue
- ret += f"\t{idprefix.upper()}TYP_{msg.name.ljust(namewidth)} = {msg.msgid},\n"
- ret += "};\n"
-
- ret += """
-/* message structs ************************************************************/
-
-"""
- for msg in structs:
- if msg.msgid is None:
- continue
- if not msg.members:
- ret += c_typename(idprefix, msg) + " {};\n"
- continue
- ret += c_typename(idprefix, msg) + " {\n"
- typewidth = max(len(c_typename(idprefix, member.typ)) for member in msg.members)
- for member in msg.members:
- ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n"
- ret += "};\n"
-
- ret += f"""
-/* tables *********************************************************************/
-
-#define _P9_TYPECODE_FOR_CTYPE(msg) """
- for msg in structs:
- if msg.msgid is None:
- continue
- ret += f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}"
- ret += "\n"
-
- ret += "\n"
- ret += f"#endif /* {guard} */\n"
- return ret
-
-
-def gen_c(txtname: str, idprefix: str, structs: list[Struct]) -> str:
- txtdir, txtbase = os.path.split(txtname)
- header = os.path.join(txtdir, "defs-" + txtbase.replace(".txt", ".h"))
- ret = f"""/* Generated by `{PROGRAM} {txtname}`. DO NOT EDIT! */
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h> /* for malloc() */
-
-#include "{header}"
-#include "9p/internal.h"
-"""
-
- def used(arg: str) -> str:
- return arg
-
- def unused(arg: str) -> str:
- return f"UNUSED({arg})"
-
- # checksize_* ##############################################################
- ret += """
-/* checksize_* ****************************************************************/
-
-static inline bool _checksize_list(size_t cnt, _checksize_fn_t fn, size_t host_size,
- uint32_t net_len, uint8_t *net_bytes, uint32_t *mut_net_offset, size_t *mut_host_extra) {
- for (size_t i = 0; i < cnt; i++)
- if (__builtin_add_overflow(*mut_host_extra, host_size, mut_host_extra)
- || fn(net_len, net_bytes, mut_net_offset, mut_host_extra))
- return true;
- return false;
-}
-
-static inline bool checksize_1(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) {
- return __builtin_add_overflow(*mut_net_offset, 1, mut_net_offset) || net_len < *mut_net_offset;
-}
-static inline bool checksize_2(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) {
- return __builtin_add_overflow(*mut_net_offset, 2, mut_net_offset) || net_len < *mut_net_offset;
-}
-static inline bool checksize_4(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) {
- return __builtin_add_overflow(*mut_net_offset, 4, mut_net_offset) || net_len < *mut_net_offset;
-}
-static inline bool checksize_8(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) {
- return __builtin_add_overflow(*mut_net_offset, 8, mut_net_offset) || net_len < *mut_net_offset;
-}
-
-"""
- for struct in structs:
- inline = ' inline' if struct.msgid is None else ''
- argfn = used if struct.members else unused
- ret += f"static{inline} bool checksize_{struct.name}(uint32_t {argfn('net_len')}, uint8_t *{argfn('net_bytes')}, uint32_t *{argfn('mut_net_offset')}, size_t *{argfn('mut_host_extra')}) {{"
- if len(struct.members) == 0:
- ret += "\n\treturn false;\n"
- ret += "}\n"
- continue
- prefix0 = "\treturn "
- prefix1 = "\t || "
- prefix2 = "\t "
- prefix = prefix0
- prev_size: int | None = None
- for member in struct.members:
- if member.cnt is not None:
- assert prev_size
- ret += f"\n{prefix }_checksize_list(decode_u{prev_size*8}le(&net_bytes[(*mut_net_offset)-{prev_size}]), checksize_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}),"
- ret += f"\n{prefix2} net_len, net_bytes, mut_net_offset, mut_host_extra)"
- else:
- ret += f"\n{prefix}checksize_{member.typ.name}(net_len, net_bytes, mut_net_offset, mut_host_extra)"
- prefix = prefix1
- prev_size = member.static_size
- if struct.name == "s":
- ret += (
- f"\n{prefix}__builtin_add_overflow(*mut_host_extra, 1, mut_host_extra)"
- )
- ret += ";\n}\n"
-
- # unmarshal_* ##############################################################
- ret += """
-/* unmarshal_* ****************************************************************/
-/* checksize_XXX() should be called before unmarshal_XXX(). */
-
-static inline bool unmarshal_1(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint8_t *out) {
- *out = decode_u8le(&net_bytes[*mut_net_offset]);
- *mut_net_offset += 1;
- return false;
-}
-static inline bool unmarshal_2(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint16_t *out) {
- *out = decode_u16le(&net_bytes[*mut_net_offset]);
- *mut_net_offset += 2;
- return false;
-}
-static inline bool unmarshal_4(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint32_t *out) {
- *out = decode_u32le(&net_bytes[*mut_net_offset]);
- *mut_net_offset += 4;
- return false;
-}
-static inline bool unmarshal_8(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint64_t *out) {
- *out = decode_u64le(&net_bytes[*mut_net_offset]);
- *mut_net_offset += 8;
- return false;
-}
-
-"""
- for struct in structs:
- argfn = used if struct.members else unused
- ret += f"static inline bool unmarshal_{struct.name}(uint8_t *{argfn('net_bytes')}, uint32_t *{argfn('mut_net_offset')}, void **{argfn('mut_host_extra')}, {c_typename(idprefix, struct)} *{argfn('out')}) {{\n"
- for member in struct.members:
- if member.cnt:
- ret += f"\tout->{member.name} = *mut_host_extra;\n"
- ret += f"\t*mut_host_extra += sizeof(*out->{member.name}) * out->{member.cnt};\n"
- ret += f"\tfor (typeof(out->{member.cnt}) i = 0; i < out->{member.cnt}; i++)\n"
- ret += f"\t\tif (unmarshal_{member.typ.name}(net_bytes, mut_net_offset, mut_host_extra, &(out->{member.name}[i])))\n"
- ret += f"\t\t\treturn true;\n"
- if struct.name == "s":
- ret += f"\tif (!is_valid_utf8_without_nul(out->{member.name}, out->{member.cnt}))\n"
- ret += f"\t\treturn true;\n"
- ret += f"\tout->{member.name}[out->{member.cnt}] = '\\0';\n"
- else:
- ret += f"\tif (unmarshal_{member.typ.name}(net_bytes, mut_net_offset, mut_host_extra, &(out->{member.name})))\n"
- ret += f"\t\treturn true;\n"
- ret += "\treturn false;\n"
- ret += "}\n"
-
- # marshal_* ################################################################
- ret += """
-/* marshal_* ******************************************************************/
-
-static inline bool marshal_1(struct p9_ctx *ctx, uint8_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) {
- if (*mut_net_offset + 1 > ctx->max_msg_size)
- return true;
- out_net_bytes[*mut_net_offset] = val;
- *mut_net_offset += 1;
- return false;
-}
-static inline bool marshal_2(struct p9_ctx *ctx, uint16_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) {
- if (*mut_net_offset + 2 > ctx->max_msg_size)
- return true;
- encode_u16le(val, &out_net_bytes[*mut_net_offset]);
- *mut_net_offset += 2;
- return false;
-}
-static inline bool marshal_4(struct p9_ctx *ctx, uint32_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) {
- if (*mut_net_offset + 4 > ctx->max_msg_size)
- return true;
- encode_u32le(val, &out_net_bytes[*mut_net_offset]);
- *mut_net_offset += 4;
- return false;
-}
-static inline bool marshal_8(struct p9_ctx *ctx, uint64_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) {
- if (*mut_net_offset + 8 > ctx->max_msg_size)
- return true;
- encode_u64le(val, &out_net_bytes[*mut_net_offset]);
- *mut_net_offset += 8;
- return false;
-}
-"""
- for struct in structs:
- argfn = used if struct.members else unused
- ret += f"static inline bool marshal_{struct.name}(struct p9_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} {argfn('val')}, uint8_t *{argfn('out_net_bytes')}, uint32_t *{argfn('mut_net_offset')}) {{\n"
- for member in struct.members:
- if member.cnt:
- ret += f"\tfor (typeof(val.{member.cnt}) i = 0; i < val.{member.cnt}; i++)\n"
- ret += f"\t\tif (marshal_{member.typ.name}(ctx, val.{member.name}[i], out_net_bytes, mut_net_offset))\n"
- ret += f"\t\t\treturn true;\n"
- else:
- ret += f"\tif (marshal_{member.typ.name}(ctx, val.{member.name}, out_net_bytes, mut_net_offset))\n"
- ret += f"\t\treturn true;\n"
- ret += "\treturn false;\n"
- ret += "}\n"
-
- # tables ###################################################################
- ret += """
-/* tables *********************************************************************/
-
-"""
- for msg in structs:
- if msg.msgid is None:
- continue
- ret += f"static bool _unmarshal_{msg.name}(uint8_t *net_bytes, uint32_t *mut_net_offset, void **mut_host_extra, void *out) {{ return unmarshal_{msg.name}(net_bytes, mut_net_offset, mut_host_extra, ({c_typename(idprefix, msg)} *)out); }}\n"
- for msg in structs:
- if msg.msgid is None:
- continue
- ret += f"static bool _marshal_{msg.name}(struct p9_ctx *ctx, void *val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) {{ return marshal_{msg.name}(ctx, *(({c_typename(idprefix, msg)} *)val), out_net_bytes, mut_net_offset); }}\n"
- ret += "struct version version_9P2000 = {\n"
- ret += "\t.msgs = {\n"
- for msg in structs:
- if msg.msgid is None:
- continue
- ret += f"\t\t[{idprefix.upper()}TYP_{msg.name}] = {{ .unmarshal_basesize=sizeof({c_typename(idprefix, msg)}), .unmarshal_extrasize=checksize_{msg.name}, .unmarshal=_unmarshal_{msg.name}, .marshal=_marshal_{msg.name} }},\n"
- ret += "\t},\n"
- ret += "};\n"
-
- ############################################################################
- return ret
-
-
-################################################################################
-
-if __name__ == "__main__":
- import sys
-
- for txtname in sys.argv[1:]:
- txtdir, txtbase = os.path.split(txtname)
- version, structs = parse_file(txtname)
- with open(
- os.path.join(txtdir, "defs-" + txtbase.replace(".txt", ".h")), "w"
- ) as fh:
- fh.write(gen_h(txtname, "p9_", structs))
- with open(
- os.path.join(txtdir, "defs-" + txtbase.replace(".txt", ".c")), "w"
- ) as fh:
- fh.write(gen_c(txtname, "p9_", structs))
diff --git a/lib9p/defs.h b/lib9p/defs.h
deleted file mode 100644
index 907cdde..0000000
--- a/lib9p/defs.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* 9p/defs.h - TODO
- *
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-Licence-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _9P_DEFS_H_
-#define _9P_DEFS_H_
-
-#include <stdint.h>
-
-#define P9_NOTAG ((uint16_t)~0U)
-#define P9_NOFID ((uint32_t)~0U)
-
-enum p9_version {
- P9_VER_UNINITIALIZED,
- /* P9_VER_9P1, */
- P9_VER_9P2000,
- /*P9_VER_9P2000_u,*/
- /*P9_VER_9P2000_L,*/
- /*P9_VER_9P2000_e,*/
- _P9_VER_CNT,
-};
-
-struct p9_ctx;
-
-enum p9_version p9_ctx_version(p9_ctx *);
-
-/** Write an static error into ctx, return -1. */
-int p9_error(struct p9_ctx *ctx, uint32_t linux_errno, char const *msg);
-/** Write a printf-style error into ctx, return -1. */
-int p9_errorf(struct p9_ctx *ctx, uint32_t linux_errno, char const *fmt, ...);
-
-/**
- * Return how much space the message at net_bytes will take when
- * unmarshaled. This number may be larger than net_bytes due to (1)
- * struct padding, (2) nul-terminator byes for strings.
- *
- * Emits an error (return -1, set ctx->err_num and ctx->err_msg) if
- * either the message type is unknown or if net_bytes is too short for
- * that message type.
- *
- * @param net_bytes : the complete request, starting with the "size[4]"
- * @return required size, or -1 on error
- */
-size_t p9_unmarshal_size(struct p9_ctx *ctx, uint8_t *net_bytes);
-
-/**
- * Unmarshal the 9P message `net_bytes` into the C struct `out_body`.
- *
- * Emits an error (return 0, set ctx->err_num and ctx->err_msg) if a
- * string contains invalid UTF-8 or a nul-byte.
- *
- * @param net_bytes : the complete message, starting with the "size[4]"
- * @param out_tag : the message-ID tag
- * @param out_body : the message body, must be at least p9_unmarshal_size() bytes
- * @return the message type, or -1 on error
- */
-uint8_t p9_unmarshal(struct p9_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, void *out_body);
-
-/**
- * Marshal a `struct p9_msg_{type}` structure into a byte-array.
- *
- * @param struct p9_ctx *ctx : a request context
- * @param uint16_t msgid : the message-ID tag
- * @param struct p9_msg_{type} msg : the message to encode
- *
- * @param uint8_t *out_bytes : the buffer to encode to, must be at be at least ctx->max_msg_size bytes
- * @return uint32_t : the encoded length, or -1 on error
- */
-#define p9_marshal(ctx, msgid, msg, out_bytes) _p9_marshal(ctx, P9_TYPECODE_FOR_CTYPE(msg), msgid, &(msg), out_bytes)
-uint32_t _p9_marshal(struct p9_ctx *ctx, uint8_t typ, uint16_t msgid, void *body, uint8_t *out_bytes);
-
-#endif /* _9P_DEFS_H_ */
diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h
new file mode 100644
index 0000000..a55f08f
--- /dev/null
+++ b/lib9p/include/lib9p/9p.h
@@ -0,0 +1,72 @@
+/* lib9p/9p.h - Base 9P protocol definitions for both clients and servers
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-Licence-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIB9P_9P_H_
+#define _LIB9P_9P_H_
+
+#include <lib9p/linux-errno.h>
+#include <lib9p/_types.h>
+
+#define LIB9P_NOTAG ((uint16_t)~0U)
+#define LIB9P_NOFID ((uint32_t)~0U)
+
+struct lib9p_ctx;
+enum lib9p_version lib9p_ctx_version(lib9p_ctx *);
+uint32_t lib9p_ctx_max_msg_size(lib9p_ctx *);
+
+/** Write an static error into ctx, return -1. */
+int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg);
+/** Write a printf-style error into ctx, return -1. */
+int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...);
+
+/**
+ * Return how much space the message at net_bytes will take when
+ * unmarshaled. This number may be larger than net_bytes due to (1)
+ * struct padding, (2) nul-terminator byes for strings.
+ *
+ * Emits an error (return -1, set ctx->err_num and ctx->err_msg) if
+ * either the message type is unknown, or if net_bytes is too short
+ * for that message type, or if an invalid string (invalid UTF-8,
+ * contains a nul-byte) is encountered.
+ *
+ * @param net_bytes : the complete request, starting with the "size[4]"
+ *
+ * @return required size, or -1 on error
+ */
+ssize_t lib9p_unmarshal_size(struct lib9p_ctx *ctx, uint8_t *net_bytes);
+
+/**
+ * Unmarshal the 9P message `net_bytes` into the C struct `ret_body`.
+ *
+ * Emits an error (return 0, set ctx->err_num and ctx->err_msg) if a
+ * string contains invalid UTF-8 or a nul-byte.
+ *
+ * @param ctx : negotiated protocol parameters, where to record errors
+ * @param net_bytes : the complete message, starting with the "size[4]"
+ *
+ * @return ret_typ : the mesage type
+ * @return ret_tag : the message-ID tag
+ * @return ret_body : the message body, must be at least lib9p_unmarshal_size() bytes
+ * @return the message type, or -1 on error
+ */
+bool lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_typ *ret_typ, uint16_t *ret_tag, void *ret_body);
+
+/**
+ * Marshal a `struct lib9p_msg_{typ}` structure into a byte-array.
+ *
+ * @param ctx : negotiated protocol parameters, where to record errors
+ * @param typ : the message type
+ * @param tag : the message-ID tag
+ * @param msg : the message to encode
+ *
+ * @return ret_bytes : the buffer to encode to, must be at be at least lib9p_ctx_max_msg_size(ctx) bytes
+ * @return whether there was an error (false=success, true=error)
+ */
+bool lib9p_marshal(struct lib9p_ctx *ctx, uint8_t typ, uint16_t tag, void *body,
+ uint8_t *ret_bytes);
+
+#endif _LIB9P_9P_H_
diff --git a/lib9p/include/lib9p/_types.h b/lib9p/include/lib9p/_types.h
new file mode 100644
index 0000000..348945d
--- /dev/null
+++ b/lib9p/include/lib9p/_types.h
@@ -0,0 +1,285 @@
+/* Generated by `./types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt`. DO NOT EDIT! */
+
+#ifndef _LIB9P__TYPES_H_
+#define _LIB9P__TYPES_H_
+
+#include <stdint.h>
+
+/* versions *******************************************************************/
+
+enum lib9p_version {
+ LIB9P_VER_UNINITIALIZED = 0,
+ LIB9P_VER_9P2000, /* "9P2000" */
+ LIB9P_VER_9P2000_e, /* "9P2000.e" */
+ LIB9P_VER_9P2000_u, /* "9P2000.u" */
+ LIB9P_VER_NUM,
+};
+
+/* non-message structs ********************************************************/
+
+struct lib9p_d {
+ uint32_t len;
+ uint8_t *dat;
+};
+
+struct lib9p_s {
+ uint16_t len;
+ uint8_t *utf8;
+};
+
+struct lib9p_qid {
+ uint8_t type;
+ uint32_t vers;
+ uint64_t path;
+};
+
+struct lib9p_stat {
+ uint16_t stat_size;
+ uint16_t kern_type;
+ uint32_t kern_dev;
+ struct lib9p_qid file_qid;
+ uint32_t file_mode;
+ uint32_t file_atime;
+ uint32_t file_mtime;
+ uint64_t file_size;
+ struct lib9p_s file_name;
+ struct lib9p_s file_owner_uid;
+ struct lib9p_s file_owner_gid;
+ struct lib9p_s file_last_modified_uid;
+ struct lib9p_s file_extension; /* 9P2000.u */
+ uint32_t file_owner_n_uid; /* 9P2000.u */
+ uint32_t file_owner_n_gid; /* 9P2000.u */
+ uint32_t file_last_modified_n_uid; /* 9P2000.u */
+};
+
+/* messages *******************************************************************/
+
+enum lib9p_msg_type { /* uint8_t */
+ LIB9P_TYP_Tversion = 100,
+ LIB9P_TYP_Rversion = 101,
+ LIB9P_TYP_Tauth = 102,
+ LIB9P_TYP_Rauth = 103,
+ LIB9P_TYP_Tattach = 104,
+ LIB9P_TYP_Rattach = 105,
+ LIB9P_TYP_Rerror = 107,
+ LIB9P_TYP_Tflush = 108,
+ LIB9P_TYP_Rflush = 109,
+ LIB9P_TYP_Twalk = 110,
+ LIB9P_TYP_Rwalk = 111,
+ LIB9P_TYP_Topen = 112,
+ LIB9P_TYP_Ropen = 113,
+ LIB9P_TYP_Tcreate = 114,
+ LIB9P_TYP_Rcreate = 115,
+ LIB9P_TYP_Tread = 116,
+ LIB9P_TYP_Rread = 117,
+ LIB9P_TYP_Twrite = 118,
+ LIB9P_TYP_Rwrite = 119,
+ LIB9P_TYP_Tclunk = 120,
+ LIB9P_TYP_Rclunk = 121,
+ LIB9P_TYP_Tremove = 122,
+ LIB9P_TYP_Rremove = 123,
+ LIB9P_TYP_Tstat = 124,
+ LIB9P_TYP_Rstat = 125,
+ LIB9P_TYP_Twstat = 126,
+ LIB9P_TYP_Rwstat = 127,
+ LIB9P_TYP_Tsession = 150, /* 9P2000.e */
+ LIB9P_TYP_Rsession = 151, /* 9P2000.e */
+ LIB9P_TYP_Tsread = 152, /* 9P2000.e */
+ LIB9P_TYP_Rsread = 153, /* 9P2000.e */
+ LIB9P_TYP_Tswrite = 154, /* 9P2000.e */
+ LIB9P_TYP_Rswrite = 155, /* 9P2000.e */
+};
+
+#define LIB9P_TYPECODE_FOR_CTYPE(msg) _Generic((msg), \
+ struct lib9p_msg_Tversion: LIB9P_TYP_Tversion, \
+ struct lib9p_msg_Rversion: LIB9P_TYP_Rversion, \
+ struct lib9p_msg_Tauth: LIB9P_TYP_Tauth, \
+ struct lib9p_msg_Rauth: LIB9P_TYP_Rauth, \
+ struct lib9p_msg_Tattach: LIB9P_TYP_Tattach, \
+ struct lib9p_msg_Rattach: LIB9P_TYP_Rattach, \
+ struct lib9p_msg_Rerror: LIB9P_TYP_Rerror, \
+ struct lib9p_msg_Tflush: LIB9P_TYP_Tflush, \
+ struct lib9p_msg_Rflush: LIB9P_TYP_Rflush, \
+ struct lib9p_msg_Twalk: LIB9P_TYP_Twalk, \
+ struct lib9p_msg_Rwalk: LIB9P_TYP_Rwalk, \
+ struct lib9p_msg_Topen: LIB9P_TYP_Topen, \
+ struct lib9p_msg_Ropen: LIB9P_TYP_Ropen, \
+ struct lib9p_msg_Tcreate: LIB9P_TYP_Tcreate, \
+ struct lib9p_msg_Rcreate: LIB9P_TYP_Rcreate, \
+ struct lib9p_msg_Tread: LIB9P_TYP_Tread, \
+ struct lib9p_msg_Rread: LIB9P_TYP_Rread, \
+ struct lib9p_msg_Twrite: LIB9P_TYP_Twrite, \
+ struct lib9p_msg_Rwrite: LIB9P_TYP_Rwrite, \
+ struct lib9p_msg_Tclunk: LIB9P_TYP_Tclunk, \
+ struct lib9p_msg_Rclunk: LIB9P_TYP_Rclunk, \
+ struct lib9p_msg_Tremove: LIB9P_TYP_Tremove, \
+ struct lib9p_msg_Rremove: LIB9P_TYP_Rremove, \
+ struct lib9p_msg_Tstat: LIB9P_TYP_Tstat, \
+ struct lib9p_msg_Rstat: LIB9P_TYP_Rstat, \
+ struct lib9p_msg_Twstat: LIB9P_TYP_Twstat, \
+ struct lib9p_msg_Rwstat: LIB9P_TYP_Rwstat, \
+ struct lib9p_msg_Tsession: LIB9P_TYP_Tsession, \
+ struct lib9p_msg_Rsession: LIB9P_TYP_Rsession, \
+ struct lib9p_msg_Tsread: LIB9P_TYP_Tsread, \
+ struct lib9p_msg_Rsread: LIB9P_TYP_Rsread, \
+ struct lib9p_msg_Tswrite: LIB9P_TYP_Tswrite, \
+ struct lib9p_msg_Rswrite: LIB9P_TYP_Rswrite)
+
+struct lib9p_msg_Tversion {
+ uint32_t max_msg_size;
+ struct lib9p_s version;
+};
+
+struct lib9p_msg_Rversion {
+ uint32_t max_msg_size;
+ struct lib9p_s version;
+};
+
+struct lib9p_msg_Tauth {
+ uint32_t afid;
+ struct lib9p_s uname;
+ struct lib9p_s aname;
+ uint32_t n_uname; /* 9P2000.u */
+};
+
+struct lib9p_msg_Rauth {
+ struct lib9p_qid aqid;
+};
+
+struct lib9p_msg_Tattach {
+ uint32_t fid;
+ uint32_t afid;
+ struct lib9p_s uname;
+ struct lib9p_s aname;
+};
+
+struct lib9p_msg_Rattach {
+ struct lib9p_qid qid;
+};
+
+struct lib9p_msg_Rerror {
+ struct lib9p_s ename;
+ uint32_t errno; /* 9P2000.u */
+};
+
+struct lib9p_msg_Tflush {
+ uint16_t oldtag;
+};
+
+struct lib9p_msg_Rflush {};
+
+struct lib9p_msg_Twalk {
+ uint32_t fid;
+ uint32_t newfid;
+ uint16_t nwname;
+ struct lib9p_s *wname;
+};
+
+struct lib9p_msg_Rwalk {
+ uint16_t nwqid;
+ struct lib9p_qid *wqid;
+};
+
+struct lib9p_msg_Topen {
+ uint32_t fid;
+ uint8_t mode;
+};
+
+struct lib9p_msg_Ropen {
+ struct lib9p_qid qid;
+ uint32_t iounit;
+};
+
+struct lib9p_msg_Tcreate {
+ uint32_t fid;
+ struct lib9p_s name;
+ uint32_t perm;
+ uint8_t mode;
+};
+
+struct lib9p_msg_Rcreate {
+ struct lib9p_qid qid;
+ uint32_t iounit;
+};
+
+struct lib9p_msg_Tread {
+ uint32_t fid;
+ uint64_t offset;
+ uint32_t count;
+};
+
+struct lib9p_msg_Rread {
+ struct lib9p_d data;
+};
+
+struct lib9p_msg_Twrite {
+ uint32_t fid;
+ uint64_t offset;
+ struct lib9p_d data;
+};
+
+struct lib9p_msg_Rwrite {
+ uint32_t count;
+};
+
+struct lib9p_msg_Tclunk {
+ uint32_t fid;
+};
+
+struct lib9p_msg_Rclunk {};
+
+struct lib9p_msg_Tremove {
+ uint32_t fid;
+};
+
+struct lib9p_msg_Rremove {};
+
+struct lib9p_msg_Tstat {
+ uint32_t fid;
+};
+
+struct lib9p_msg_Rstat {
+ struct lib9p_stat stat;
+};
+
+struct lib9p_msg_Twstat {
+ uint32_t fid;
+ struct lib9p_stat stat;
+};
+
+struct lib9p_msg_Rwstat {};
+
+/* 9P2000.e */
+struct lib9p_msg_Tsession {
+ uint64_t key;
+};
+
+/* 9P2000.e */
+struct lib9p_msg_Rsession {};
+
+/* 9P2000.e */
+struct lib9p_msg_Tsread {
+ uint32_t fid;
+ uint16_t nwname;
+ struct lib9p_s *wname;
+};
+
+/* 9P2000.e */
+struct lib9p_msg_Rsread {
+ struct lib9p_d data;
+};
+
+/* 9P2000.e */
+struct lib9p_msg_Tswrite {
+ uint32_t fid;
+ uint16_t nwname;
+ struct lib9p_s *wname;
+ struct lib9p_d data;
+};
+
+/* 9P2000.e */
+struct lib9p_msg_Rswrite {
+ uint32_t count;
+};
+
+#endif /* _LIB9P__TYPES_H_ */
diff --git a/lib9p/linux-errno.h.gen b/lib9p/include/lib9p/linux-errno.h.gen
index b896384..b896384 100755
--- a/lib9p/linux-errno.h.gen
+++ b/lib9p/include/lib9p/linux-errno.h.gen
diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h
new file mode 100644
index 0000000..3b8b21e
--- /dev/null
+++ b/lib9p/include/lib9p/srv.h
@@ -0,0 +1,16 @@
+#ifndef _LIB9P_SRV_H_
+#define _LIB9P_SRV_H_
+
+#include <libcr/coroutine.h>
+
+struct lib9p_srvreq;
+
+struct lib9p_srv {
+ int sockfd;
+ cr_chan_t(lib9p_srvreq *) reqch;
+};
+
+COROUTINE lib9p_srv_read_cr(void *_srv);
+COROUTINE lib9p_srv_write_cr(void *_srv);
+
+#endif /* _LIB9P_SRV_H_ */
diff --git a/lib9p/internal.h b/lib9p/internal.h
index 61977d4..ebdc3f3 100644
--- a/lib9p/internal.h
+++ b/lib9p/internal.h
@@ -1,21 +1,20 @@
-/* 9p/internal.h - TODO
+/* lib9p/internal.h - TODO
*
* Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-Licence-Identifier: AGPL-3.0-or-later
*/
-#ifndef _9P_INTERNAL_H_
-#define _9P_INTERNAL_H_
+#ifndef _LIB9P_INTERNAL_H_
+#define _LIB9P_INTERNAL_H_
#include <assert.h>
-#include <stdint.h>
#include <stdbool.h>
-#include "9p/defs.h"
+#include <lib9p/9p.h>
-#define USE_CONFIG_9P
+#define USE_CONFIG_LIB9P
#include "config.h"
-static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX);
+static_assert(CONFIG_LIB9P_MAX_ERR_SIZE <= UINT16_MAX);
/* C language *****************************************************************/
@@ -23,39 +22,65 @@ static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX);
/* types **********************************************************************/
-struct p9_ctx {
- enum p9_version version;
- uint32_t max_msg_size;
- uint32_t Rerror_overhead;
+/* NB: We declare this here instead of in the public <lib9p/9p.h>
+ * because we don't want to include "config.h" from public headers,
+ * and I want the MAX_ERR_SIZE to be configurable. */
+struct lib9p_ctx {
+ /* negotiated */
+ enum lib9p_version version;
+ uint32_t max_msg_size;
+ /* negotiated (server) */
+ uint32_t Rerror_overhead;
+
+ /* state */
+ uint32_t err_num;
+ char err_msg[CONFIG_LIB9P_MAX_ERR_SIZE];
+};
+
+/* vtables ********************************************************************/
- uint32_t err_num;
- char err_msg[CONFIG_9P_MAX_ERR_SIZE];
+struct _checksize_ctx {
+ struct lib9p_ctx *ctx;
+ uint32_t net_size;
+ uint8_t net_bytes;
+
+ uint32_t net_offset;
+ /* Increment `host_extra` to pre-allocate space that is
+ * "extra" beyond sizeof(). */
+ size_t host_extra;
};
-static inline enum p9_version p9_ctx_version(p9_ctx *ctx) {
- assert(ctx);
- return ctx->version;
-}
+struct _unmarshal_ctx {
+ struct lib9p_ctx *ctx;
-/* vtables ********************************************************************/
+ uint32_t net_offset;
+ /* `extra` points to the beginning of unallocated space. */
+ void *extra;
+};
+
+struct _marshal_ctx {
+ struct lib9p_ctx *ctx;
+
+ uint8_t *net_bytes;
+ uint32_t net_offset;
+};
-typedef bool (*_checksize_fn_t)(uint32_t net_len, uint8_t *net_bytes, uint32_t *mut_net_offset, size_t *mut_host_extra);
-typedef bool (*_unmarshal_fn_t)(uint8_t *net_bytes, uint32_t *mut_net_offset, void **mut_host_extra, void *out);
-typedef bool (*_marshal_fn_t)(struct p9_ctx *ctx, void *val, uint8_t *out_net_bytes, uint32_t *mut_net_offset);
+typedef bool (*_checksize_fn_t)(struct _checksize_ctx *ctx);
+typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out);
+typedef bool (*_marshal_fn_t)(struct _marshal_ctx *ctx, void *host_val);
-struct msg_vtable {
+struct _vtable_msg {
size_t unmarshal_basesize;
_checksize_fn_t unmarshal_extrasize;
_unmarshal_fn_t unmarshal;
_marshal_fn_t marshal;
};
-struct version {
- struct msg_vtable msgs[0xFF];
+struct _vtable_version {
+ struct _vtable_msg msgs[0xFF];
};
-extern struct version version_9P2000;
-/*extern struct version version_9P2000u; */
+extern struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM];
/* unmarshal utilities ********************************************************/
@@ -136,4 +161,4 @@ static inline void encode_u64le(uint64_t in, uint8_t *out) {
out[7] = (uint8_t)((in >> 56) & 0xFF);
}
-#endif /* _9P_INTERNAL_H_ */
+#endif /* _LIB9P_INTERNAL_H_ */
diff --git a/lib9p/misc.txt b/lib9p/misc.txt
deleted file mode 100644
index 93aa304..0000000
--- a/lib9p/misc.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-# qid.types
-QTDIR = 1<<7
-QTAPPEND = 1<<6
-QTEXCL = 1<<5
-QTMOUNT = 1<<4 # been around forever, but undocumented?
-QTAUTH = 1<<3
-QTTMP = 1<<2 # added to Plan 9 2003-12
-QTSYMLINK = 1<<1 # .u
-QTFILE = 1<<0
-
-DMDIR = 1<<31
-DMAPPEND = 1<<30
-DMEXCL = 1<<29
-DMMOUNT = 1<<28
-DMAUTH = 1<<27
-DMTMP = 1<<26
-# = 1<<25
-# = 1<<24
-DMDEVICE = 1<<23 # .u
-# = 1<<22
-DMNAMEDPIPE = 1<<21 # .u
-DMSOCKET = 1<<20 # .u
-DMSETUID = 1<<19 # .u
-DMSETGID = 1<<18 # .u
diff --git a/lib9p/srv.h b/lib9p/srv.h
deleted file mode 100644
index e3623ed..0000000
--- a/lib9p/srv.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _NET9P_H_
-#define _NET9P_H_
-
-#include "coroutine.h"
-
-struct p9_srvreq;
-
-struct p9_srv {
- int sockfd;
- cr_chan_t(p9_srvreq *) reqch;
-};
-
-COROUTINE p9_srv_read_cr(void *_srv);
-COROUTINE p9_srv_write_cr(void *_srv);
-
-#endif /* _NET9P_H_ */
diff --git a/lib9p/types.c b/lib9p/types.c
new file mode 100644
index 0000000..73ac28e
--- /dev/null
+++ b/lib9p/types.c
@@ -0,0 +1,1331 @@
+/* Generated by `./types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt`. DO NOT EDIT! */
+
+#include <stdbool.h>
+
+#include <lib9p/9p.h>
+
+#include "internal.h"
+
+/* checksize_* (internals of unmarshal_size()) ********************************/
+
+static inline bool _checksize_net(struct _checksize_ctx *ctx, uint32_t n) {
+ if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset))
+ /* If needed-net-size overflowed uint32_t, then
+ * there's no way that actual-net-size will live up to
+ * that. */
+ return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
+ if (ctx->net_offset > ctx->net_size)
+ return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
+ return false;
+}
+
+static inline bool _checksize_host(struct _checksize_ctx *ctx, size_t n) {
+ if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra))
+ /* If needed-host-size overflowed size_t, then there's
+ * no way that actual-net-size will live up to
+ * that. */
+ return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
+ return false;
+}
+
+static inline bool _checksize_list(struct _checksize_ctx *ctx,
+ size_t cnt, _checksize_fn_t item_fn, size_t item_host_size) {
+ for (size_t i = 0; i < cnt; i++)
+ if (_checksize_host(ctx, item_host_size) || item_fn(ctx))
+ return true;
+ return false;
+}
+
+#define checksize_1(ctx) _checksize_net(ctx, 1)
+#define checksize_2(ctx) _checksize_net(ctx, 2)
+#define checksize_4(ctx) _checksize_net(ctx, 4)
+#define checksize_8(ctx) _checksize_net(ctx, 8)
+
+static inline bool checksize_d(struct _checksize_ctx *ctx) {
+ uint32_t base_offset = ctx->net_offset;
+ if (_checksize_4(ctx))
+ return true;
+ uint32_t len = decode_u32le(&ctx->net_bytes[base_offset]);
+ return checksize_net(ctx, len) || checksize_host(ctx, len);
+}
+
+static inline bool checksize_s(struct _checksize_ctx *ctx) {
+ uint32_t base_offset = ctx->net_offset;
+ if (_checksize_2(ctx))
+ return true;
+ uint16_t len = decode_u16le(&ctx->net_bytes[base_offset]);
+ if (checksize_net(ctx, len) || checksize_host(ctx, ((size_t)len)+1))
+ return true;
+ if (!is_valid_utf8_without_nul(&ctx->net_bytes[base_offset+2], len))
+ return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8");
+ return false;
+}
+
+static inline bool checksize_qid(struct _checksize_ctx *ctx) {
+ return checksize_1(ctx)
+ || checksize_4(ctx)
+ || checksize_8(ctx);
+}
+
+static inline bool checksize_stat(struct _checksize_ctx *ctx) {
+ return checksize_2(ctx)
+ || checksize_2(ctx)
+ || checksize_4(ctx)
+ || checksize_qid(ctx)
+ || checksize_4(ctx)
+ || checksize_4(ctx)
+ || checksize_4(ctx)
+ || checksize_8(ctx)
+ || checksize_s(ctx)
+ || checksize_s(ctx)
+ || checksize_s(ctx)
+ || checksize_s(ctx)
+ || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_s(ctx) )
+ || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) )
+ || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) )
+ || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) );
+}
+
+static bool checksize_Tversion(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_s(ctx);
+}
+
+static bool checksize_Rversion(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_s(ctx);
+}
+
+static bool checksize_Tauth(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_s(ctx)
+ || checksize_s(ctx)
+ || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) );
+}
+
+static bool checksize_Rauth(struct _checksize_ctx *ctx) {
+ return checksize_qid(ctx);
+}
+
+static bool checksize_Tattach(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_4(ctx)
+ || checksize_s(ctx)
+ || checksize_s(ctx);
+}
+
+static bool checksize_Rattach(struct _checksize_ctx *ctx) {
+ return checksize_qid(ctx);
+}
+
+static bool checksize_Rerror(struct _checksize_ctx *ctx) {
+ return checksize_s(ctx)
+ || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) );
+}
+
+static bool checksize_Tflush(struct _checksize_ctx *ctx) {
+ return checksize_2(ctx);
+}
+
+static bool checksize_Rflush(struct _checksize_ctx *UNUSED(ctx)) {
+ return false;
+}
+
+static bool checksize_Twalk(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_4(ctx)
+ || checksize_2(ctx)
+ || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_s, sizeof(struct lib9p_s));
+}
+
+static bool checksize_Rwalk(struct _checksize_ctx *ctx) {
+ return checksize_2(ctx)
+ || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_qid, sizeof(struct lib9p_qid));
+}
+
+static bool checksize_Topen(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_1(ctx);
+}
+
+static bool checksize_Ropen(struct _checksize_ctx *ctx) {
+ return checksize_qid(ctx)
+ || checksize_4(ctx);
+}
+
+static bool checksize_Tcreate(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_s(ctx)
+ || checksize_4(ctx)
+ || checksize_1(ctx);
+}
+
+static bool checksize_Rcreate(struct _checksize_ctx *ctx) {
+ return checksize_qid(ctx)
+ || checksize_4(ctx);
+}
+
+static bool checksize_Tread(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_8(ctx)
+ || checksize_4(ctx);
+}
+
+static bool checksize_Rread(struct _checksize_ctx *ctx) {
+ return checksize_d(ctx);
+}
+
+static bool checksize_Twrite(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_8(ctx)
+ || checksize_d(ctx);
+}
+
+static bool checksize_Rwrite(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx);
+}
+
+static bool checksize_Tclunk(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx);
+}
+
+static bool checksize_Rclunk(struct _checksize_ctx *UNUSED(ctx)) {
+ return false;
+}
+
+static bool checksize_Tremove(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx);
+}
+
+static bool checksize_Rremove(struct _checksize_ctx *UNUSED(ctx)) {
+ return false;
+}
+
+static bool checksize_Tstat(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx);
+}
+
+static bool checksize_Rstat(struct _checksize_ctx *ctx) {
+ return checksize_stat(ctx);
+}
+
+static bool checksize_Twstat(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_stat(ctx);
+}
+
+static bool checksize_Rwstat(struct _checksize_ctx *UNUSED(ctx)) {
+ return false;
+}
+
+static bool checksize_Tsession(struct _checksize_ctx *ctx) {
+ return checksize_8(ctx);
+}
+
+static bool checksize_Rsession(struct _checksize_ctx *UNUSED(ctx)) {
+ return false;
+}
+
+static bool checksize_Tsread(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_2(ctx)
+ || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_s, sizeof(struct lib9p_s));
+}
+
+static bool checksize_Rsread(struct _checksize_ctx *ctx) {
+ return checksize_d(ctx);
+}
+
+static bool checksize_Tswrite(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx)
+ || checksize_2(ctx)
+ || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_s, sizeof(struct lib9p_s))
+ || checksize_d(ctx);
+}
+
+static bool checksize_Rswrite(struct _checksize_ctx *ctx) {
+ return checksize_4(ctx);
+}
+
+/* unmarshal_* ****************************************************************/
+
+static inline vold unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) {
+ *out = decode_u8le(&ctx->net_bytes[ctx->net_offset]);
+ ctx->net_offset += 1;
+}
+
+static inline vold unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) {
+ *out = decode_u16le(&ctx->net_bytes[ctx->net_offset]);
+ ctx->net_offset += 2;
+}
+
+static inline vold unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) {
+ *out = decode_u32le(&ctx->net_bytes[ctx->net_offset]);
+ ctx->net_offset += 4;
+}
+
+static inline vold unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) {
+ *out = decode_u64le(&ctx->net_bytes[ctx->net_offset]);
+ ctx->net_offset += 8;
+}
+
+static inline void unmarshal_d(struct _unmarshal_ctx *ctx, struct lib9p_d *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->len);
+ out->dat = ctx->host_extra;
+ ctx->host_extra += sizeof(out->dat[0]) * out->len;
+ for (typeof(out->len) i = 0; i < out->len; i++)
+ unmarshal_1(ctx, &out->dat[i]);
+}
+
+static inline void unmarshal_s(struct _unmarshal_ctx *ctx, struct lib9p_s *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_2(ctx, &out->len);
+ out->utf8 = ctx->host_extra;
+ ctx->host_extra += sizeof(out->utf8[0]) * out->len;
+ for (typeof(out->len) i = 0; i < out->len; i++)
+ unmarshal_1(ctx, &out->utf8[i]);
+}
+
+static inline void unmarshal_qid(struct _unmarshal_ctx *ctx, struct lib9p_qid *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_1(ctx, &out->type);
+ unmarshal_4(ctx, &out->vers);
+ unmarshal_8(ctx, &out->path);
+}
+
+static inline void unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_2(ctx, &out->stat_size);
+ unmarshal_2(ctx, &out->kern_type);
+ unmarshal_4(ctx, &out->kern_dev);
+ unmarshal_qid(ctx, &out->file_qid);
+ unmarshal_4(ctx, &out->file_mode);
+ unmarshal_4(ctx, &out->file_atime);
+ unmarshal_4(ctx, &out->file_mtime);
+ unmarshal_8(ctx, &out->file_size);
+ unmarshal_s(ctx, &out->file_name);
+ unmarshal_s(ctx, &out->file_owner_uid);
+ unmarshal_s(ctx, &out->file_owner_gid);
+ unmarshal_s(ctx, &out->file_last_modified_uid);
+ if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_s(ctx, &out->file_extension);
+ if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_uid);
+ if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_gid);
+ if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_last_modified_n_uid);
+}
+
+static void unmarshal_Tversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tversion *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->max_msg_size);
+ unmarshal_s(ctx, &out->version);
+}
+
+static void unmarshal_Rversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rversion *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->max_msg_size);
+ unmarshal_s(ctx, &out->version);
+}
+
+static void unmarshal_Tauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tauth *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->afid);
+ unmarshal_s(ctx, &out->uname);
+ unmarshal_s(ctx, &out->aname);
+ if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->n_uname);
+}
+
+static void unmarshal_Rauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rauth *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_qid(ctx, &out->aqid);
+}
+
+static void unmarshal_Tattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tattach *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+ unmarshal_4(ctx, &out->afid);
+ unmarshal_s(ctx, &out->uname);
+ unmarshal_s(ctx, &out->aname);
+}
+
+static void unmarshal_Rattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rattach *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_qid(ctx, &out->qid);
+}
+
+static void unmarshal_Rerror(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rerror *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_s(ctx, &out->ename);
+ if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->errno);
+}
+
+static void unmarshal_Tflush(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tflush *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_2(ctx, &out->oldtag);
+}
+
+static void unmarshal_Rflush(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rflush *UNUSED(out)) {
+ memset(out, 0, sizeof(*out));
+}
+
+static void unmarshal_Twalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twalk *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+ unmarshal_4(ctx, &out->newfid);
+ unmarshal_2(ctx, &out->nwname);
+ out->wname = ctx->host_extra;
+ ctx->host_extra += sizeof(out->wname[0]) * out->nwname;
+ for (typeof(out->nwname) i = 0; i < out->nwname; i++)
+ unmarshal_s(ctx, &out->wname[i]);
+}
+
+static void unmarshal_Rwalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwalk *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_2(ctx, &out->nwqid);
+ out->wqid = ctx->host_extra;
+ ctx->host_extra += sizeof(out->wqid[0]) * out->nwqid;
+ for (typeof(out->nwqid) i = 0; i < out->nwqid; i++)
+ unmarshal_qid(ctx, &out->wqid[i]);
+}
+
+static void unmarshal_Topen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Topen *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+ unmarshal_1(ctx, &out->mode);
+}
+
+static void unmarshal_Ropen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Ropen *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_qid(ctx, &out->qid);
+ unmarshal_4(ctx, &out->iounit);
+}
+
+static void unmarshal_Tcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tcreate *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+ unmarshal_s(ctx, &out->name);
+ unmarshal_4(ctx, &out->perm);
+ unmarshal_1(ctx, &out->mode);
+}
+
+static void unmarshal_Rcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rcreate *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_qid(ctx, &out->qid);
+ unmarshal_4(ctx, &out->iounit);
+}
+
+static void unmarshal_Tread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tread *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+ unmarshal_8(ctx, &out->offset);
+ unmarshal_4(ctx, &out->count);
+}
+
+static void unmarshal_Rread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rread *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_d(ctx, &out->data);
+}
+
+static void unmarshal_Twrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twrite *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+ unmarshal_8(ctx, &out->offset);
+ unmarshal_d(ctx, &out->data);
+}
+
+static void unmarshal_Rwrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwrite *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->count);
+}
+
+static void unmarshal_Tclunk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tclunk *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+}
+
+static void unmarshal_Rclunk(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rclunk *UNUSED(out)) {
+ memset(out, 0, sizeof(*out));
+}
+
+static void unmarshal_Tremove(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tremove *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+}
+
+static void unmarshal_Rremove(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rremove *UNUSED(out)) {
+ memset(out, 0, sizeof(*out));
+}
+
+static void unmarshal_Tstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tstat *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+}
+
+static void unmarshal_Rstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rstat *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_stat(ctx, &out->stat);
+}
+
+static void unmarshal_Twstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twstat *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+ unmarshal_stat(ctx, &out->stat);
+}
+
+static void unmarshal_Rwstat(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rwstat *UNUSED(out)) {
+ memset(out, 0, sizeof(*out));
+}
+
+static void unmarshal_Tsession(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsession *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_8(ctx, &out->key);
+}
+
+static void unmarshal_Rsession(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rsession *UNUSED(out)) {
+ memset(out, 0, sizeof(*out));
+}
+
+static void unmarshal_Tsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsread *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+ unmarshal_2(ctx, &out->nwname);
+ out->wname = ctx->host_extra;
+ ctx->host_extra += sizeof(out->wname[0]) * out->nwname;
+ for (typeof(out->nwname) i = 0; i < out->nwname; i++)
+ unmarshal_s(ctx, &out->wname[i]);
+}
+
+static void unmarshal_Rsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsread *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_d(ctx, &out->data);
+}
+
+static void unmarshal_Tswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tswrite *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->fid);
+ unmarshal_2(ctx, &out->nwname);
+ out->wname = ctx->host_extra;
+ ctx->host_extra += sizeof(out->wname[0]) * out->nwname;
+ for (typeof(out->nwname) i = 0; i < out->nwname; i++)
+ unmarshal_s(ctx, &out->wname[i]);
+ unmarshal_d(ctx, &out->data);
+}
+
+static void unmarshal_Rswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rswrite *out) {
+ memset(out, 0, sizeof(*out));
+ unmarshal_4(ctx, &out->count);
+}
+
+/* marshal_* ******************************************************************/
+
+static inline bool _marshal_too_large(struct _marshal_ctx *ctx) {
+ lib9p_errorf(ctx->ctx, "%s too large to marshal into %s limit (limit=%"PRIu32")",
+ (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message",
+ ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"),
+ ctx->ctx->max_msg_size));
+ return true;
+}
+
+static inline bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) {
+ if (ctx->net_offset + 1 > ctx->max_msg_size)
+ return _marshal_too_large(ctx);
+ out_net_bytes[ctx->net_offset] = *val;
+ ctx->net_offset += 1;
+ return false;
+}
+
+static inline bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) {
+ if (ctx->net_offset + 2 > ctx->max_msg_size)
+ return _marshal_too_large(ctx);
+ encode_u16le(*val, &out_net_bytes[ctx->net_offset]);
+ ctx->net_offset += 2;
+ return false;
+}
+
+static inline bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) {
+ if (ctx->net_offset + 4 > ctx->max_msg_size)
+ return true;
+ encode_u32le(*val, &out_net_bytes[ctx->net_offset]);
+ ctx->net_offset += 4;
+ return false;
+}
+
+static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) {
+ if (ctx->net_offset + 8 > ctx->max_msg_size)
+ return true;
+ encode_u64le(*val, &out_net_bytes[ctx->net_offset]);
+ ctx->net_offset += 8;
+ return false;
+}
+
+static inline bool marshal_d(struct _marshal_ctx *ctx, struct lib9p_d *val) {
+ return marshal_4(ctx, &val->len)
+ || ({
+ bool err = false;
+ for (typeof(val->len) i = 0; i < val->len && !err; i++)
+ err = marshal_1(ctx, &val->dat[i]));
+ err;
+ });
+}
+
+static inline bool marshal_s(struct _marshal_ctx *ctx, struct lib9p_s *val) {
+ return marshal_2(ctx, &val->len)
+ || ({
+ bool err = false;
+ for (typeof(val->len) i = 0; i < val->len && !err; i++)
+ err = marshal_1(ctx, &val->utf8[i]));
+ err;
+ });
+}
+
+static inline bool marshal_qid(struct _marshal_ctx *ctx, struct lib9p_qid *val) {
+ return marshal_1(ctx, &val->type)
+ || marshal_4(ctx, &val->vers)
+ || marshal_8(ctx, &val->path);
+}
+
+static inline bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) {
+ return marshal_2(ctx, &val->stat_size)
+ || marshal_2(ctx, &val->kern_type)
+ || marshal_4(ctx, &val->kern_dev)
+ || marshal_qid(ctx, &val->file_qid)
+ || marshal_4(ctx, &val->file_mode)
+ || marshal_4(ctx, &val->file_atime)
+ || marshal_4(ctx, &val->file_mtime)
+ || marshal_8(ctx, &val->file_size)
+ || marshal_s(ctx, &val->file_name)
+ || marshal_s(ctx, &val->file_owner_uid)
+ || marshal_s(ctx, &val->file_owner_gid)
+ || marshal_s(ctx, &val->file_last_modified_uid)
+ || marshal_s(ctx, &val->file_extension)
+ || marshal_4(ctx, &val->file_owner_n_uid)
+ || marshal_4(ctx, &val->file_owner_n_gid)
+ || marshal_4(ctx, &val->file_last_modified_n_uid);
+}
+
+static bool marshal_Tversion(struct _marshal_ctx *ctx, struct lib9p_msg_Tversion *val) {
+ return marshal_4(ctx, &val->max_msg_size)
+ || marshal_s(ctx, &val->version);
+}
+
+static bool marshal_Rversion(struct _marshal_ctx *ctx, struct lib9p_msg_Rversion *val) {
+ return marshal_4(ctx, &val->max_msg_size)
+ || marshal_s(ctx, &val->version);
+}
+
+static bool marshal_Tauth(struct _marshal_ctx *ctx, struct lib9p_msg_Tauth *val) {
+ return marshal_4(ctx, &val->afid)
+ || marshal_s(ctx, &val->uname)
+ || marshal_s(ctx, &val->aname)
+ || marshal_4(ctx, &val->n_uname);
+}
+
+static bool marshal_Rauth(struct _marshal_ctx *ctx, struct lib9p_msg_Rauth *val) {
+ return marshal_qid(ctx, &val->aqid);
+}
+
+static bool marshal_Tattach(struct _marshal_ctx *ctx, struct lib9p_msg_Tattach *val) {
+ return marshal_4(ctx, &val->fid)
+ || marshal_4(ctx, &val->afid)
+ || marshal_s(ctx, &val->uname)
+ || marshal_s(ctx, &val->aname);
+}
+
+static bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach *val) {
+ return marshal_qid(ctx, &val->qid);
+}
+
+static bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *val) {
+ return marshal_s(ctx, &val->ename)
+ || marshal_4(ctx, &val->errno);
+}
+
+static bool marshal_Tflush(struct _marshal_ctx *ctx, struct lib9p_msg_Tflush *val) {
+ return marshal_2(ctx, &val->oldtag);
+}
+
+static bool marshal_Rflush(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rflush *UNUSED(val)) {
+ return false;
+}
+
+static bool marshal_Twalk(struct _marshal_ctx *ctx, struct lib9p_msg_Twalk *val) {
+ return marshal_4(ctx, &val->fid)
+ || marshal_4(ctx, &val->newfid)
+ || marshal_2(ctx, &val->nwname)
+ || ({
+ bool err = false;
+ for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++)
+ err = marshal_s(ctx, &val->wname[i]));
+ err;
+ });
+}
+
+static bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) {
+ return marshal_2(ctx, &val->nwqid)
+ || ({
+ bool err = false;
+ for (typeof(val->nwqid) i = 0; i < val->nwqid && !err; i++)
+ err = marshal_qid(ctx, &val->wqid[i]));
+ err;
+ });
+}
+
+static bool marshal_Topen(struct _marshal_ctx *ctx, struct lib9p_msg_Topen *val) {
+ return marshal_4(ctx, &val->fid)
+ || marshal_1(ctx, &val->mode);
+}
+
+static bool marshal_Ropen(struct _marshal_ctx *ctx, struct lib9p_msg_Ropen *val) {
+ return marshal_qid(ctx, &val->qid)
+ || marshal_4(ctx, &val->iounit);
+}
+
+static bool marshal_Tcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tcreate *val) {
+ return marshal_4(ctx, &val->fid)
+ || marshal_s(ctx, &val->name)
+ || marshal_4(ctx, &val->perm)
+ || marshal_1(ctx, &val->mode);
+}
+
+static bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate *val) {
+ return marshal_qid(ctx, &val->qid)
+ || marshal_4(ctx, &val->iounit);
+}
+
+static bool marshal_Tread(struct _marshal_ctx *ctx, struct lib9p_msg_Tread *val) {
+ return marshal_4(ctx, &val->fid)
+ || marshal_8(ctx, &val->offset)
+ || marshal_4(ctx, &val->count);
+}
+
+static bool marshal_Rread(struct _marshal_ctx *ctx, struct lib9p_msg_Rread *val) {
+ return marshal_d(ctx, &val->data);
+}
+
+static bool marshal_Twrite(struct _marshal_ctx *ctx, struct lib9p_msg_Twrite *val) {
+ return marshal_4(ctx, &val->fid)
+ || marshal_8(ctx, &val->offset)
+ || marshal_d(ctx, &val->data);
+}
+
+static bool marshal_Rwrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rwrite *val) {
+ return marshal_4(ctx, &val->count);
+}
+
+static bool marshal_Tclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Tclunk *val) {
+ return marshal_4(ctx, &val->fid);
+}
+
+static bool marshal_Rclunk(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rclunk *UNUSED(val)) {
+ return false;
+}
+
+static bool marshal_Tremove(struct _marshal_ctx *ctx, struct lib9p_msg_Tremove *val) {
+ return marshal_4(ctx, &val->fid);
+}
+
+static bool marshal_Rremove(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rremove *UNUSED(val)) {
+ return false;
+}
+
+static bool marshal_Tstat(struct _marshal_ctx *ctx, struct lib9p_msg_Tstat *val) {
+ return marshal_4(ctx, &val->fid);
+}
+
+static bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) {
+ return marshal_stat(ctx, &val->stat);
+}
+
+static bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *val) {
+ return marshal_4(ctx, &val->fid)
+ || marshal_stat(ctx, &val->stat);
+}
+
+static bool marshal_Rwstat(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rwstat *UNUSED(val)) {
+ return false;
+}
+
+static bool marshal_Tsession(struct _marshal_ctx *ctx, struct lib9p_msg_Tsession *val) {
+ return marshal_8(ctx, &val->key);
+}
+
+static bool marshal_Rsession(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rsession *UNUSED(val)) {
+ return false;
+}
+
+static bool marshal_Tsread(struct _marshal_ctx *ctx, struct lib9p_msg_Tsread *val) {
+ return marshal_4(ctx, &val->fid)
+ || marshal_2(ctx, &val->nwname)
+ || ({
+ bool err = false;
+ for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++)
+ err = marshal_s(ctx, &val->wname[i]));
+ err;
+ });
+}
+
+static bool marshal_Rsread(struct _marshal_ctx *ctx, struct lib9p_msg_Rsread *val) {
+ return marshal_d(ctx, &val->data);
+}
+
+static bool marshal_Tswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Tswrite *val) {
+ return marshal_4(ctx, &val->fid)
+ || marshal_2(ctx, &val->nwname)
+ || ({
+ bool err = false;
+ for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++)
+ err = marshal_s(ctx, &val->wname[i]));
+ err;
+ })
+ || marshal_d(ctx, &val->data);
+}
+
+static bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite *val) {
+ return marshal_4(ctx, &val->count);
+}
+
+/* vtables ********************************************************************/
+
+struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM] = {
+ [LIB9P_VER_UNINITIALIZED] = {
+ [LIB9P_TYP_Tversion] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion),
+ r.unmarshal_extrasize = checksize_Tversion,
+ r.unmarshal = unmarshal_Tversion,
+ r.marshal = (_marshal_fn_t)marshal_Tversion,
+ },
+ [LIB9P_TYP_Rversion] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion),
+ r.unmarshal_extrasize = checksize_Rversion,
+ r.unmarshal = unmarshal_Rversion,
+ r.marshal = (_marshal_fn_t)marshal_Rversion,
+ },
+ },
+ [LIB9P_VER_9P2000] = {
+ [LIB9P_TYP_Tversion] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion),
+ r.unmarshal_extrasize = checksize_Tversion,
+ r.unmarshal = unmarshal_Tversion,
+ r.marshal = (_marshal_fn_t)marshal_Tversion,
+ },
+ [LIB9P_TYP_Rversion] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion),
+ r.unmarshal_extrasize = checksize_Rversion,
+ r.unmarshal = unmarshal_Rversion,
+ r.marshal = (_marshal_fn_t)marshal_Rversion,
+ },
+ [LIB9P_TYP_Tauth] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tauth),
+ r.unmarshal_extrasize = checksize_Tauth,
+ r.unmarshal = unmarshal_Tauth,
+ r.marshal = (_marshal_fn_t)marshal_Tauth,
+ },
+ [LIB9P_TYP_Rauth] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rauth),
+ r.unmarshal_extrasize = checksize_Rauth,
+ r.unmarshal = unmarshal_Rauth,
+ r.marshal = (_marshal_fn_t)marshal_Rauth,
+ },
+ [LIB9P_TYP_Tattach] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tattach),
+ r.unmarshal_extrasize = checksize_Tattach,
+ r.unmarshal = unmarshal_Tattach,
+ r.marshal = (_marshal_fn_t)marshal_Tattach,
+ },
+ [LIB9P_TYP_Rattach] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rattach),
+ r.unmarshal_extrasize = checksize_Rattach,
+ r.unmarshal = unmarshal_Rattach,
+ r.marshal = (_marshal_fn_t)marshal_Rattach,
+ },
+ [LIB9P_TYP_Rerror] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rerror),
+ r.unmarshal_extrasize = checksize_Rerror,
+ r.unmarshal = unmarshal_Rerror,
+ r.marshal = (_marshal_fn_t)marshal_Rerror,
+ },
+ [LIB9P_TYP_Tflush] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tflush),
+ r.unmarshal_extrasize = checksize_Tflush,
+ r.unmarshal = unmarshal_Tflush,
+ r.marshal = (_marshal_fn_t)marshal_Tflush,
+ },
+ [LIB9P_TYP_Rflush] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rflush),
+ r.unmarshal_extrasize = checksize_Rflush,
+ r.unmarshal = unmarshal_Rflush,
+ r.marshal = (_marshal_fn_t)marshal_Rflush,
+ },
+ [LIB9P_TYP_Twalk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Twalk),
+ r.unmarshal_extrasize = checksize_Twalk,
+ r.unmarshal = unmarshal_Twalk,
+ r.marshal = (_marshal_fn_t)marshal_Twalk,
+ },
+ [LIB9P_TYP_Rwalk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwalk),
+ r.unmarshal_extrasize = checksize_Rwalk,
+ r.unmarshal = unmarshal_Rwalk,
+ r.marshal = (_marshal_fn_t)marshal_Rwalk,
+ },
+ [LIB9P_TYP_Topen] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Topen),
+ r.unmarshal_extrasize = checksize_Topen,
+ r.unmarshal = unmarshal_Topen,
+ r.marshal = (_marshal_fn_t)marshal_Topen,
+ },
+ [LIB9P_TYP_Ropen] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Ropen),
+ r.unmarshal_extrasize = checksize_Ropen,
+ r.unmarshal = unmarshal_Ropen,
+ r.marshal = (_marshal_fn_t)marshal_Ropen,
+ },
+ [LIB9P_TYP_Tcreate] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tcreate),
+ r.unmarshal_extrasize = checksize_Tcreate,
+ r.unmarshal = unmarshal_Tcreate,
+ r.marshal = (_marshal_fn_t)marshal_Tcreate,
+ },
+ [LIB9P_TYP_Rcreate] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rcreate),
+ r.unmarshal_extrasize = checksize_Rcreate,
+ r.unmarshal = unmarshal_Rcreate,
+ r.marshal = (_marshal_fn_t)marshal_Rcreate,
+ },
+ [LIB9P_TYP_Tread] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tread),
+ r.unmarshal_extrasize = checksize_Tread,
+ r.unmarshal = unmarshal_Tread,
+ r.marshal = (_marshal_fn_t)marshal_Tread,
+ },
+ [LIB9P_TYP_Rread] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rread),
+ r.unmarshal_extrasize = checksize_Rread,
+ r.unmarshal = unmarshal_Rread,
+ r.marshal = (_marshal_fn_t)marshal_Rread,
+ },
+ [LIB9P_TYP_Twrite] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Twrite),
+ r.unmarshal_extrasize = checksize_Twrite,
+ r.unmarshal = unmarshal_Twrite,
+ r.marshal = (_marshal_fn_t)marshal_Twrite,
+ },
+ [LIB9P_TYP_Rwrite] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwrite),
+ r.unmarshal_extrasize = checksize_Rwrite,
+ r.unmarshal = unmarshal_Rwrite,
+ r.marshal = (_marshal_fn_t)marshal_Rwrite,
+ },
+ [LIB9P_TYP_Tclunk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tclunk),
+ r.unmarshal_extrasize = checksize_Tclunk,
+ r.unmarshal = unmarshal_Tclunk,
+ r.marshal = (_marshal_fn_t)marshal_Tclunk,
+ },
+ [LIB9P_TYP_Rclunk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rclunk),
+ r.unmarshal_extrasize = checksize_Rclunk,
+ r.unmarshal = unmarshal_Rclunk,
+ r.marshal = (_marshal_fn_t)marshal_Rclunk,
+ },
+ [LIB9P_TYP_Tremove] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tremove),
+ r.unmarshal_extrasize = checksize_Tremove,
+ r.unmarshal = unmarshal_Tremove,
+ r.marshal = (_marshal_fn_t)marshal_Tremove,
+ },
+ [LIB9P_TYP_Rremove] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rremove),
+ r.unmarshal_extrasize = checksize_Rremove,
+ r.unmarshal = unmarshal_Rremove,
+ r.marshal = (_marshal_fn_t)marshal_Rremove,
+ },
+ [LIB9P_TYP_Tstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tstat),
+ r.unmarshal_extrasize = checksize_Tstat,
+ r.unmarshal = unmarshal_Tstat,
+ r.marshal = (_marshal_fn_t)marshal_Tstat,
+ },
+ [LIB9P_TYP_Rstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rstat),
+ r.unmarshal_extrasize = checksize_Rstat,
+ r.unmarshal = unmarshal_Rstat,
+ r.marshal = (_marshal_fn_t)marshal_Rstat,
+ },
+ [LIB9P_TYP_Twstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Twstat),
+ r.unmarshal_extrasize = checksize_Twstat,
+ r.unmarshal = unmarshal_Twstat,
+ r.marshal = (_marshal_fn_t)marshal_Twstat,
+ },
+ [LIB9P_TYP_Rwstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwstat),
+ r.unmarshal_extrasize = checksize_Rwstat,
+ r.unmarshal = unmarshal_Rwstat,
+ r.marshal = (_marshal_fn_t)marshal_Rwstat,
+ },
+ },
+ [LIB9P_VER_9P2000_e] = {
+ [LIB9P_TYP_Tversion] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion),
+ r.unmarshal_extrasize = checksize_Tversion,
+ r.unmarshal = unmarshal_Tversion,
+ r.marshal = (_marshal_fn_t)marshal_Tversion,
+ },
+ [LIB9P_TYP_Rversion] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion),
+ r.unmarshal_extrasize = checksize_Rversion,
+ r.unmarshal = unmarshal_Rversion,
+ r.marshal = (_marshal_fn_t)marshal_Rversion,
+ },
+ [LIB9P_TYP_Tauth] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tauth),
+ r.unmarshal_extrasize = checksize_Tauth,
+ r.unmarshal = unmarshal_Tauth,
+ r.marshal = (_marshal_fn_t)marshal_Tauth,
+ },
+ [LIB9P_TYP_Rauth] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rauth),
+ r.unmarshal_extrasize = checksize_Rauth,
+ r.unmarshal = unmarshal_Rauth,
+ r.marshal = (_marshal_fn_t)marshal_Rauth,
+ },
+ [LIB9P_TYP_Tattach] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tattach),
+ r.unmarshal_extrasize = checksize_Tattach,
+ r.unmarshal = unmarshal_Tattach,
+ r.marshal = (_marshal_fn_t)marshal_Tattach,
+ },
+ [LIB9P_TYP_Rattach] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rattach),
+ r.unmarshal_extrasize = checksize_Rattach,
+ r.unmarshal = unmarshal_Rattach,
+ r.marshal = (_marshal_fn_t)marshal_Rattach,
+ },
+ [LIB9P_TYP_Rerror] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rerror),
+ r.unmarshal_extrasize = checksize_Rerror,
+ r.unmarshal = unmarshal_Rerror,
+ r.marshal = (_marshal_fn_t)marshal_Rerror,
+ },
+ [LIB9P_TYP_Tflush] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tflush),
+ r.unmarshal_extrasize = checksize_Tflush,
+ r.unmarshal = unmarshal_Tflush,
+ r.marshal = (_marshal_fn_t)marshal_Tflush,
+ },
+ [LIB9P_TYP_Rflush] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rflush),
+ r.unmarshal_extrasize = checksize_Rflush,
+ r.unmarshal = unmarshal_Rflush,
+ r.marshal = (_marshal_fn_t)marshal_Rflush,
+ },
+ [LIB9P_TYP_Twalk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Twalk),
+ r.unmarshal_extrasize = checksize_Twalk,
+ r.unmarshal = unmarshal_Twalk,
+ r.marshal = (_marshal_fn_t)marshal_Twalk,
+ },
+ [LIB9P_TYP_Rwalk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwalk),
+ r.unmarshal_extrasize = checksize_Rwalk,
+ r.unmarshal = unmarshal_Rwalk,
+ r.marshal = (_marshal_fn_t)marshal_Rwalk,
+ },
+ [LIB9P_TYP_Topen] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Topen),
+ r.unmarshal_extrasize = checksize_Topen,
+ r.unmarshal = unmarshal_Topen,
+ r.marshal = (_marshal_fn_t)marshal_Topen,
+ },
+ [LIB9P_TYP_Ropen] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Ropen),
+ r.unmarshal_extrasize = checksize_Ropen,
+ r.unmarshal = unmarshal_Ropen,
+ r.marshal = (_marshal_fn_t)marshal_Ropen,
+ },
+ [LIB9P_TYP_Tcreate] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tcreate),
+ r.unmarshal_extrasize = checksize_Tcreate,
+ r.unmarshal = unmarshal_Tcreate,
+ r.marshal = (_marshal_fn_t)marshal_Tcreate,
+ },
+ [LIB9P_TYP_Rcreate] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rcreate),
+ r.unmarshal_extrasize = checksize_Rcreate,
+ r.unmarshal = unmarshal_Rcreate,
+ r.marshal = (_marshal_fn_t)marshal_Rcreate,
+ },
+ [LIB9P_TYP_Tread] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tread),
+ r.unmarshal_extrasize = checksize_Tread,
+ r.unmarshal = unmarshal_Tread,
+ r.marshal = (_marshal_fn_t)marshal_Tread,
+ },
+ [LIB9P_TYP_Rread] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rread),
+ r.unmarshal_extrasize = checksize_Rread,
+ r.unmarshal = unmarshal_Rread,
+ r.marshal = (_marshal_fn_t)marshal_Rread,
+ },
+ [LIB9P_TYP_Twrite] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Twrite),
+ r.unmarshal_extrasize = checksize_Twrite,
+ r.unmarshal = unmarshal_Twrite,
+ r.marshal = (_marshal_fn_t)marshal_Twrite,
+ },
+ [LIB9P_TYP_Rwrite] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwrite),
+ r.unmarshal_extrasize = checksize_Rwrite,
+ r.unmarshal = unmarshal_Rwrite,
+ r.marshal = (_marshal_fn_t)marshal_Rwrite,
+ },
+ [LIB9P_TYP_Tclunk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tclunk),
+ r.unmarshal_extrasize = checksize_Tclunk,
+ r.unmarshal = unmarshal_Tclunk,
+ r.marshal = (_marshal_fn_t)marshal_Tclunk,
+ },
+ [LIB9P_TYP_Rclunk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rclunk),
+ r.unmarshal_extrasize = checksize_Rclunk,
+ r.unmarshal = unmarshal_Rclunk,
+ r.marshal = (_marshal_fn_t)marshal_Rclunk,
+ },
+ [LIB9P_TYP_Tremove] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tremove),
+ r.unmarshal_extrasize = checksize_Tremove,
+ r.unmarshal = unmarshal_Tremove,
+ r.marshal = (_marshal_fn_t)marshal_Tremove,
+ },
+ [LIB9P_TYP_Rremove] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rremove),
+ r.unmarshal_extrasize = checksize_Rremove,
+ r.unmarshal = unmarshal_Rremove,
+ r.marshal = (_marshal_fn_t)marshal_Rremove,
+ },
+ [LIB9P_TYP_Tstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tstat),
+ r.unmarshal_extrasize = checksize_Tstat,
+ r.unmarshal = unmarshal_Tstat,
+ r.marshal = (_marshal_fn_t)marshal_Tstat,
+ },
+ [LIB9P_TYP_Rstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rstat),
+ r.unmarshal_extrasize = checksize_Rstat,
+ r.unmarshal = unmarshal_Rstat,
+ r.marshal = (_marshal_fn_t)marshal_Rstat,
+ },
+ [LIB9P_TYP_Twstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Twstat),
+ r.unmarshal_extrasize = checksize_Twstat,
+ r.unmarshal = unmarshal_Twstat,
+ r.marshal = (_marshal_fn_t)marshal_Twstat,
+ },
+ [LIB9P_TYP_Rwstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwstat),
+ r.unmarshal_extrasize = checksize_Rwstat,
+ r.unmarshal = unmarshal_Rwstat,
+ r.marshal = (_marshal_fn_t)marshal_Rwstat,
+ },
+ [LIB9P_TYP_Tsession] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tsession),
+ r.unmarshal_extrasize = checksize_Tsession,
+ r.unmarshal = unmarshal_Tsession,
+ r.marshal = (_marshal_fn_t)marshal_Tsession,
+ },
+ [LIB9P_TYP_Rsession] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rsession),
+ r.unmarshal_extrasize = checksize_Rsession,
+ r.unmarshal = unmarshal_Rsession,
+ r.marshal = (_marshal_fn_t)marshal_Rsession,
+ },
+ [LIB9P_TYP_Tsread] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tsread),
+ r.unmarshal_extrasize = checksize_Tsread,
+ r.unmarshal = unmarshal_Tsread,
+ r.marshal = (_marshal_fn_t)marshal_Tsread,
+ },
+ [LIB9P_TYP_Rsread] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rsread),
+ r.unmarshal_extrasize = checksize_Rsread,
+ r.unmarshal = unmarshal_Rsread,
+ r.marshal = (_marshal_fn_t)marshal_Rsread,
+ },
+ [LIB9P_TYP_Tswrite] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tswrite),
+ r.unmarshal_extrasize = checksize_Tswrite,
+ r.unmarshal = unmarshal_Tswrite,
+ r.marshal = (_marshal_fn_t)marshal_Tswrite,
+ },
+ [LIB9P_TYP_Rswrite] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rswrite),
+ r.unmarshal_extrasize = checksize_Rswrite,
+ r.unmarshal = unmarshal_Rswrite,
+ r.marshal = (_marshal_fn_t)marshal_Rswrite,
+ },
+ },
+ [LIB9P_VER_9P2000_u] = {
+ [LIB9P_TYP_Tversion] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion),
+ r.unmarshal_extrasize = checksize_Tversion,
+ r.unmarshal = unmarshal_Tversion,
+ r.marshal = (_marshal_fn_t)marshal_Tversion,
+ },
+ [LIB9P_TYP_Rversion] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion),
+ r.unmarshal_extrasize = checksize_Rversion,
+ r.unmarshal = unmarshal_Rversion,
+ r.marshal = (_marshal_fn_t)marshal_Rversion,
+ },
+ [LIB9P_TYP_Tauth] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tauth),
+ r.unmarshal_extrasize = checksize_Tauth,
+ r.unmarshal = unmarshal_Tauth,
+ r.marshal = (_marshal_fn_t)marshal_Tauth,
+ },
+ [LIB9P_TYP_Rauth] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rauth),
+ r.unmarshal_extrasize = checksize_Rauth,
+ r.unmarshal = unmarshal_Rauth,
+ r.marshal = (_marshal_fn_t)marshal_Rauth,
+ },
+ [LIB9P_TYP_Tattach] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tattach),
+ r.unmarshal_extrasize = checksize_Tattach,
+ r.unmarshal = unmarshal_Tattach,
+ r.marshal = (_marshal_fn_t)marshal_Tattach,
+ },
+ [LIB9P_TYP_Rattach] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rattach),
+ r.unmarshal_extrasize = checksize_Rattach,
+ r.unmarshal = unmarshal_Rattach,
+ r.marshal = (_marshal_fn_t)marshal_Rattach,
+ },
+ [LIB9P_TYP_Rerror] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rerror),
+ r.unmarshal_extrasize = checksize_Rerror,
+ r.unmarshal = unmarshal_Rerror,
+ r.marshal = (_marshal_fn_t)marshal_Rerror,
+ },
+ [LIB9P_TYP_Tflush] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tflush),
+ r.unmarshal_extrasize = checksize_Tflush,
+ r.unmarshal = unmarshal_Tflush,
+ r.marshal = (_marshal_fn_t)marshal_Tflush,
+ },
+ [LIB9P_TYP_Rflush] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rflush),
+ r.unmarshal_extrasize = checksize_Rflush,
+ r.unmarshal = unmarshal_Rflush,
+ r.marshal = (_marshal_fn_t)marshal_Rflush,
+ },
+ [LIB9P_TYP_Twalk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Twalk),
+ r.unmarshal_extrasize = checksize_Twalk,
+ r.unmarshal = unmarshal_Twalk,
+ r.marshal = (_marshal_fn_t)marshal_Twalk,
+ },
+ [LIB9P_TYP_Rwalk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwalk),
+ r.unmarshal_extrasize = checksize_Rwalk,
+ r.unmarshal = unmarshal_Rwalk,
+ r.marshal = (_marshal_fn_t)marshal_Rwalk,
+ },
+ [LIB9P_TYP_Topen] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Topen),
+ r.unmarshal_extrasize = checksize_Topen,
+ r.unmarshal = unmarshal_Topen,
+ r.marshal = (_marshal_fn_t)marshal_Topen,
+ },
+ [LIB9P_TYP_Ropen] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Ropen),
+ r.unmarshal_extrasize = checksize_Ropen,
+ r.unmarshal = unmarshal_Ropen,
+ r.marshal = (_marshal_fn_t)marshal_Ropen,
+ },
+ [LIB9P_TYP_Tcreate] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tcreate),
+ r.unmarshal_extrasize = checksize_Tcreate,
+ r.unmarshal = unmarshal_Tcreate,
+ r.marshal = (_marshal_fn_t)marshal_Tcreate,
+ },
+ [LIB9P_TYP_Rcreate] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rcreate),
+ r.unmarshal_extrasize = checksize_Rcreate,
+ r.unmarshal = unmarshal_Rcreate,
+ r.marshal = (_marshal_fn_t)marshal_Rcreate,
+ },
+ [LIB9P_TYP_Tread] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tread),
+ r.unmarshal_extrasize = checksize_Tread,
+ r.unmarshal = unmarshal_Tread,
+ r.marshal = (_marshal_fn_t)marshal_Tread,
+ },
+ [LIB9P_TYP_Rread] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rread),
+ r.unmarshal_extrasize = checksize_Rread,
+ r.unmarshal = unmarshal_Rread,
+ r.marshal = (_marshal_fn_t)marshal_Rread,
+ },
+ [LIB9P_TYP_Twrite] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Twrite),
+ r.unmarshal_extrasize = checksize_Twrite,
+ r.unmarshal = unmarshal_Twrite,
+ r.marshal = (_marshal_fn_t)marshal_Twrite,
+ },
+ [LIB9P_TYP_Rwrite] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwrite),
+ r.unmarshal_extrasize = checksize_Rwrite,
+ r.unmarshal = unmarshal_Rwrite,
+ r.marshal = (_marshal_fn_t)marshal_Rwrite,
+ },
+ [LIB9P_TYP_Tclunk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tclunk),
+ r.unmarshal_extrasize = checksize_Tclunk,
+ r.unmarshal = unmarshal_Tclunk,
+ r.marshal = (_marshal_fn_t)marshal_Tclunk,
+ },
+ [LIB9P_TYP_Rclunk] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rclunk),
+ r.unmarshal_extrasize = checksize_Rclunk,
+ r.unmarshal = unmarshal_Rclunk,
+ r.marshal = (_marshal_fn_t)marshal_Rclunk,
+ },
+ [LIB9P_TYP_Tremove] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tremove),
+ r.unmarshal_extrasize = checksize_Tremove,
+ r.unmarshal = unmarshal_Tremove,
+ r.marshal = (_marshal_fn_t)marshal_Tremove,
+ },
+ [LIB9P_TYP_Rremove] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rremove),
+ r.unmarshal_extrasize = checksize_Rremove,
+ r.unmarshal = unmarshal_Rremove,
+ r.marshal = (_marshal_fn_t)marshal_Rremove,
+ },
+ [LIB9P_TYP_Tstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Tstat),
+ r.unmarshal_extrasize = checksize_Tstat,
+ r.unmarshal = unmarshal_Tstat,
+ r.marshal = (_marshal_fn_t)marshal_Tstat,
+ },
+ [LIB9P_TYP_Rstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rstat),
+ r.unmarshal_extrasize = checksize_Rstat,
+ r.unmarshal = unmarshal_Rstat,
+ r.marshal = (_marshal_fn_t)marshal_Rstat,
+ },
+ [LIB9P_TYP_Twstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Twstat),
+ r.unmarshal_extrasize = checksize_Twstat,
+ r.unmarshal = unmarshal_Twstat,
+ r.marshal = (_marshal_fn_t)marshal_Twstat,
+ },
+ [LIB9P_TYP_Rwstat] = {
+ r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwstat),
+ r.unmarshal_extrasize = checksize_Rwstat,
+ r.unmarshal = unmarshal_Rwstat,
+ r.marshal = (_marshal_fn_t)marshal_Rwstat,
+ },
+ },
+};
diff --git a/lib9p/types.gen b/lib9p/types.gen
new file mode 100755
index 0000000..141b591
--- /dev/null
+++ b/lib9p/types.gen
@@ -0,0 +1,611 @@
+#!/usr/bin/env python
+# lib9p/types.gen - Generate C marshalers/unmarshalers for .txt files
+# defining 9P protocol variants.
+#
+# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-Licence-Identifier: AGPL-3.0-or-later
+
+import enum
+import os.path
+import re
+from typing import Callable
+
+# Parse *.txt ##################################################################
+
+
+class Atom(enum.Enum):
+ u8 = 1
+ u16 = 2
+ u32 = 4
+ u64 = 8
+
+ @property
+ def name(self) -> str:
+ return str(self.value)
+
+ @property
+ def static_size(self) -> int:
+ return self.value
+
+
+# `msgid/structname = "member1 member2..."`
+# `structname = "member1 member2..."`
+# `structname += "member1 member2..."`
+class Struct:
+ msgid: int | None = None
+ msgver: set[str]
+ name: str
+ members: list["Member"]
+
+ def __init__(self) -> None:
+ self.msgver = set()
+
+ @property
+ def static_size(self) -> int | None:
+ size = 0
+ for member in self.members:
+ msize = member.static_size
+ if msize is None:
+ return None
+ size += msize
+ return size
+
+
+# `cnt*(name[typ])`
+# the `cnt*(...)` wrapper is optional
+class Member:
+ cnt: str | None = None
+ name: str
+ typ: Atom | Struct
+ ver: set[str]
+
+ @property
+ def static_size(self) -> int | None:
+ if self.cnt:
+ return None
+ return self.typ.static_size
+
+
+re_membername = "(?:[a-zA-Z_][a-zA-Z_0-9]*)"
+re_memberspec = (
+ f"(?:(?P<cnt>{re_membername})\\*\\()?(?P<name>{re_membername})\\[(?P<typ>.*)\\]\\)?"
+)
+
+
+def parse_members(
+ ver: str,
+ env: dict[str, Atom | Struct], existing: list[Member], specs: str
+) -> list[Member]:
+ ret = existing
+ for spec in specs.split():
+ m = re.fullmatch(re_memberspec, spec)
+ if not m:
+ raise SyntaxError(f"invalid member spec {repr(spec)}")
+
+ member = Member()
+ member.ver = {ver}
+
+ member.name = m.group("name")
+ if any(x.name == member.name for x in ret):
+ raise ValueError(f"duplicate member name {repr(member.name)}")
+
+ if m.group("typ") not in env:
+ raise NameError(f"Unknown type {repr(m.group(2))}")
+ member.typ = env[m.group("typ")]
+
+ if cnt := m.group("cnt"):
+ if len(ret) == 0 or ret[-1].name != cnt:
+ raise ValueError(f"list count must be previous item: {repr(cnt)}")
+ if not isinstance(ret[-1].typ, Atom):
+ raise ValueError(f"list count must be an integer type: {repr(cnt)}")
+ member.cnt = cnt
+
+ ret += [member]
+ return ret
+
+
+re_version = r'version\s+"(?P<version>[^"]+)"'
+re_import = r'from\s+(?P<file>\S+)\s+import\s+(?P<syms>\S+(?:\s*,\s*\S+)*)\s*'
+re_structspec = (
+ r'(?:(?P<msgid>[0-9]+)/)?(?P<name>\S+)\s*(?P<op>\+?=)\s*"(?P<members>[^"]*)"'
+)
+re_structspec_cont = r'"(?P<members>[^"]*)"'
+
+
+def parse_file(filename: str, get_include: Callable[[str], tuple[str, list[Struct]]]) -> tuple[str, list[Struct]]:
+ version: str | None = None
+ env: dict[str, Atom | Struct] = {
+ "1": Atom.u8,
+ "2": Atom.u16,
+ "4": Atom.u32,
+ "8": Atom.u64,
+ }
+ with open(filename, "r") as fh:
+ prev: Struct | None = None
+ for line in fh:
+ line = line.split("#", 1)[0].strip()
+ if not line:
+ continue
+ if m := re.fullmatch(re_version, line):
+ if version:
+ raise SyntaxError("must have exactly 1 version line")
+ version = m.group("version")
+ elif m := re.fullmatch(re_import, line):
+ if not version:
+ raise SyntaxError("must have exactly 1 version line")
+ other_version, other_structs = get_include(m.group("file"))
+ for symname in m.group("syms").split(sep=","):
+ symname = symname.strip()
+ for struct in other_structs:
+ if struct.name == symname or symname == '*':
+ if struct.msgid:
+ struct.msgver.add(version)
+ for member in struct.members:
+ if other_version in member.ver:
+ member.ver.add(version)
+ env[struct.name] = struct
+ elif m := re.fullmatch(re_structspec, line):
+ if not version:
+ raise SyntaxError("must have exactly 1 version line")
+ if m.group("op") == "+=" and m.group("msgid"):
+ raise SyntaxError("cannot += to a message that is not yet defined")
+ match m.group("op"):
+ case "=":
+ struct = Struct()
+ if m.group("msgid"):
+ struct.msgid = int(m.group("msgid"))
+ struct.msgver.add(version)
+ struct.name = m.group("name")
+ struct.members = parse_members(version, env, [], m.group("members"))
+ env[struct.name] = struct
+ prev = struct
+ case "+=":
+ if m.group("name") not in env:
+ raise NameError(f"Unknown type {repr(m.group('name'))}")
+ _struct = env[m.group("name")]
+ if not isinstance(_struct, Struct):
+ raise NameError(
+ f"Type {repr(m.group('name'))} is not a struct"
+ )
+ struct = _struct
+ struct.members = parse_members(version,
+ env, struct.members, m.group("members")
+ )
+ prev = struct
+ elif m := re.fullmatch(re_structspec_cont, line):
+ if not prev:
+ raise SyntaxError("continuation line must come after a struct line")
+ assert(version)
+ prev.members = parse_members(version, env, prev.members, m.group("members"))
+ else:
+ raise SyntaxError(f"invalid line {repr(line)}")
+ if not version:
+ raise SyntaxError("must have exactly 1 version line")
+ structs = [x for x in env.values() if isinstance(x, Struct)]
+ return version, structs
+
+# Generate C ###################################################################
+
+
+def c_typename(idprefix: str, typ: Atom | Struct) -> str:
+ match typ:
+ case Atom():
+ return f"uint{typ.value*8}_t"
+ case Struct():
+ if typ.msgid is not None:
+ return f"struct {idprefix}msg_{typ.name}"
+ return f"struct {idprefix}{typ.name}"
+ case _:
+ raise ValueError(f"not a type: {typ.__class__.__name__}")
+
+def c_vercomment(versions: set[str]) -> str|None:
+ if "9P2000" in versions:
+ return None
+ return "/* "+(", ".join(sorted(versions)))+" */"
+
+def c_ver(idprefix: str, ver: str) -> str:
+ return f"{idprefix.upper()}VER_{ver.replace('.', '_')}"
+
+def gen_h(idprefix: str, versions: set[str], structs: list[Struct]) -> str:
+ guard = "_LIB9P__TYPES_H_"
+ ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */
+
+#ifndef {guard}
+#define {guard}
+
+#include <stdint.h>
+"""
+
+ ret += f"""
+/* versions *******************************************************************/
+
+enum {idprefix}version {{
+ {idprefix.upper()}VER_UNINITIALIZED = 0,
+"""
+ verwidth = max(len(v) for v in versions)
+ for ver in sorted(versions):
+ ret += f"\t{c_ver(idprefix, ver)},"
+ ret += (" "*(verwidth-len(ver))) + ' /* "' + ver + '" */\n'
+ ret += f"\t{idprefix.upper()}VER_NUM,\n"
+ ret += "};\n"
+
+ ret += """
+/* non-message structs ********************************************************/
+"""
+ for struct in structs:
+ if struct.msgid is not None:
+ continue
+
+ all_the_same = len(struct.members) == 0 or all(m.ver == struct.members[0].ver for m in struct.members)
+ typewidth = max(len(c_typename(idprefix, m.typ)) for m in struct.members)
+ if not all_the_same:
+ namewidth = max(len(m.name) for m in struct.members)
+
+ ret += "\n"
+ ret += c_typename(idprefix, struct) + " {\n"
+ for member in struct.members:
+ ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};"
+ if (not all_the_same) and (comment := c_vercomment(member.ver)):
+ ret += (" "*(namewidth-len(member.name))) + " " + comment
+ ret += "\n"
+ ret += "};\n"
+
+ ret += """
+/* messages *******************************************************************/
+
+"""
+ ret += f"enum {idprefix}msg_type {{ /* uint8_t */\n"
+ namewidth = max(len(msg.name) for msg in structs if msg.msgid is not None)
+ for msg in structs:
+ if msg.msgid is None:
+ continue
+ ret += f"\t{idprefix.upper()}TYP_{msg.name.ljust(namewidth)} = {msg.msgid},"
+ if (comment := c_vercomment(msg.msgver)):
+ ret += " " + comment
+ ret += "\n"
+ ret += "};\n"
+
+ ret += "\n"
+ ret += f"#define {idprefix.upper()}TYPECODE_FOR_CTYPE(msg) _Generic((msg)"
+ for msg in structs:
+ if msg.msgid is None:
+ continue
+ ret += f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}"
+ ret += ")\n"
+
+ for msg in structs:
+ if msg.msgid is None:
+ continue
+
+ ret += "\n"
+ if comment := c_vercomment(msg.msgver):
+ ret += comment + "\n"
+ ret += c_typename(idprefix, msg) + " {"
+ if not msg.members:
+ ret += "};\n"
+ continue
+ ret += "\n"
+
+ all_the_same = len(msg.members) == 0 or all(m.ver == msg.members[0].ver for m in msg.members)
+ typewidth = max(len(c_typename(idprefix, m.typ)) for m in msg.members)
+ if not all_the_same:
+ namewidth = max(len(m.name) for m in msg.members)
+
+ for member in msg.members:
+ ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};"
+ if (not all_the_same) and (comment := c_vercomment(member.ver)):
+ ret += (" "*(namewidth-len(member.name))) + " " + comment
+ ret += "\n"
+ ret += "};\n"
+
+
+ ret += "\n"
+ ret += f"#endif /* {guard} */\n"
+ return ret
+
+
+def gen_c(idprefix: str, versions: set[str], structs: list[Struct]) -> str:
+ ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */
+
+#include <stdbool.h>
+
+#include <lib9p/9p.h>
+
+#include "internal.h"
+"""
+
+ def used(arg: str) -> str:
+ return arg
+
+ def unused(arg: str) -> str:
+ return f"UNUSED({arg})"
+
+ # checksize_* ##############################################################
+ ret += """
+/* checksize_* (internals of unmarshal_size()) ********************************/
+
+static inline bool _checksize_net(struct _checksize_ctx *ctx, uint32_t n) {
+ if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset))
+ /* If needed-net-size overflowed uint32_t, then
+ * there's no way that actual-net-size will live up to
+ * that. */
+ return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
+ if (ctx->net_offset > ctx->net_size)
+ return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
+ return false;
+}
+
+static inline bool _checksize_host(struct _checksize_ctx *ctx, size_t n) {
+ if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra))
+ /* If needed-host-size overflowed size_t, then there's
+ * no way that actual-net-size will live up to
+ * that. */
+ return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
+ return false;
+}
+
+static inline bool _checksize_list(struct _checksize_ctx *ctx,
+ size_t cnt, _checksize_fn_t item_fn, size_t item_host_size) {
+ for (size_t i = 0; i < cnt; i++)
+ if (_checksize_host(ctx, item_host_size) || item_fn(ctx))
+ return true;
+ return false;
+}
+
+#define checksize_1(ctx) _checksize_net(ctx, 1)
+#define checksize_2(ctx) _checksize_net(ctx, 2)
+#define checksize_4(ctx) _checksize_net(ctx, 4)
+#define checksize_8(ctx) _checksize_net(ctx, 8)
+"""
+ for struct in structs:
+ inline = ' inline' if struct.msgid is None else ''
+ argfn = used if struct.members else unused
+ ret += "\n"
+ ret += f"static{inline} bool checksize_{struct.name}(struct _checksize_ctx *{argfn('ctx')}) {{"
+ if len(struct.members) == 0:
+ ret += "\n\treturn false;\n"
+ ret += "}\n"
+ continue
+
+ prefix0 = "\treturn "
+ prefix1 = "\t || "
+
+ match struct.name:
+ case "d":
+ # Optimize... maybe the compiler could figure out to do
+ # this, but let's make it obvious.
+ ret += "\n"
+ ret += "\tuint32_t base_offset = ctx->net_offset;\n"
+ ret += "\tif (_checksize_4(ctx))\n"
+ ret += "\t\treturn true;\n"
+ ret += "\tuint32_t len = decode_u32le(&ctx->net_bytes[base_offset]);\n"
+ ret += "\treturn checksize_net(ctx, len) || checksize_host(ctx, len);\n"
+ ret += "}\n"
+ case "s":
+ # Add an extra nul-byte on the host, and validate
+ # UTF-8 (also, similar optimization to "d").
+ ret += "\n"
+ ret += "\tuint32_t base_offset = ctx->net_offset;\n"
+ ret += "\tif (_checksize_2(ctx))\n"
+ ret += "\t\treturn true;\n"
+ ret += "\tuint16_t len = decode_u16le(&ctx->net_bytes[base_offset]);\n"
+ ret += "\tif (checksize_net(ctx, len) || checksize_host(ctx, ((size_t)len)+1))\n"
+ ret += "\t\treturn true;\n"
+ ret += "\tif (!is_valid_utf8_without_nul(&ctx->net_bytes[base_offset+2], len))\n"
+ ret += '\t\treturn lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8");\n'
+ ret += "\treturn false;\n"
+ ret += "}\n"
+ case _:
+ struct_versions = struct.members[0].ver
+
+ prefix = prefix0
+ prev_size: int | None = None
+ for member in struct.members:
+ ret += f"\n{prefix}"
+ if member.ver != struct_versions:
+ ret += "( ( " + (" || ".join(f"(ctx->ctx->version=={c_ver(idprefix, v)})" for v in sorted(member.ver))) + " ) && "
+ if member.cnt is not None:
+ assert prev_size
+ ret += f"_checksize_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), checksize_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))"
+ else:
+ ret += f"checksize_{member.typ.name}(ctx)"
+ if member.ver != struct_versions:
+ ret += " )"
+ prefix = prefix1
+ prev_size = member.static_size
+ ret += ";\n}\n"
+
+ # unmarshal_* ##############################################################
+ ret += """
+/* unmarshal_* ****************************************************************/
+
+static inline vold unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) {
+ *out = decode_u8le(&ctx->net_bytes[ctx->net_offset]);
+ ctx->net_offset += 1;
+}
+
+static inline vold unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) {
+ *out = decode_u16le(&ctx->net_bytes[ctx->net_offset]);
+ ctx->net_offset += 2;
+}
+
+static inline vold unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) {
+ *out = decode_u32le(&ctx->net_bytes[ctx->net_offset]);
+ ctx->net_offset += 4;
+}
+
+static inline vold unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) {
+ *out = decode_u64le(&ctx->net_bytes[ctx->net_offset]);
+ ctx->net_offset += 8;
+}
+"""
+ for struct in structs:
+ inline = ' inline' if struct.msgid is None else ''
+ argfn = used if struct.members else unused
+ ret += "\n"
+ ret += f"static{inline} void unmarshal_{struct.name}(struct _unmarshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *{argfn('out')}) {{\n"
+ ret += "\tmemset(out, 0, sizeof(*out));\n"
+
+ if struct.members:
+ struct_versions = struct.members[0].ver
+ for member in struct.members:
+ ret += "\t"
+ prefix = "\t"
+ if member.ver != struct_versions:
+ ret += "if ( " + (" || ".join(f"(ctx->ctx->version=={c_ver(idprefix, v)})" for v in sorted(member.ver))) + " ) "
+ prefix = "\t\t"
+ if member.cnt:
+ if member.ver != struct_versions:
+ ret += "{\n"
+ ret += f"{prefix}out->{member.name} = ctx->host_extra;\n"
+ ret += f"{prefix}ctx->host_extra += sizeof(out->{member.name}[0]) * out->{member.cnt};\n"
+ ret += f"{prefix}for (typeof(out->{member.cnt}) i = 0; i < out->{member.cnt}; i++)\n"
+ ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, &out->{member.name}[i]);\n"
+ if member.ver != struct_versions:
+ ret += "\t}\n"
+ else:
+ ret += f"unmarshal_{member.typ.name}(ctx, &out->{member.name});\n"
+ ret += "}\n"
+
+ # marshal_* ################################################################
+ ret += """
+/* marshal_* ******************************************************************/
+
+static inline bool _marshal_too_large(struct _marshal_ctx *ctx) {
+ lib9p_errorf(ctx->ctx, "%s too large to marshal into %s limit (limit=%"PRIu32")",
+ (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message",
+ ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"),
+ ctx->ctx->max_msg_size));
+ return true;
+}
+
+static inline bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) {
+ if (ctx->net_offset + 1 > ctx->max_msg_size)
+ return _marshal_too_large(ctx);
+ out_net_bytes[ctx->net_offset] = *val;
+ ctx->net_offset += 1;
+ return false;
+}
+
+static inline bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) {
+ if (ctx->net_offset + 2 > ctx->max_msg_size)
+ return _marshal_too_large(ctx);
+ encode_u16le(*val, &out_net_bytes[ctx->net_offset]);
+ ctx->net_offset += 2;
+ return false;
+}
+
+static inline bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) {
+ if (ctx->net_offset + 4 > ctx->max_msg_size)
+ return true;
+ encode_u32le(*val, &out_net_bytes[ctx->net_offset]);
+ ctx->net_offset += 4;
+ return false;
+}
+
+static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) {
+ if (ctx->net_offset + 8 > ctx->max_msg_size)
+ return true;
+ encode_u64le(*val, &out_net_bytes[ctx->net_offset]);
+ ctx->net_offset += 8;
+ return false;
+}
+"""
+ for struct in structs:
+ inline = ' inline' if struct.msgid is None else ''
+ argfn = used if struct.members else unused
+ ret += "\n"
+ ret += f"static{inline} bool marshal_{struct.name}(struct _marshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *{argfn('val')}) {{"
+ if len(struct.members) == 0:
+ ret += "\n\treturn false;\n"
+ ret += "}\n"
+ continue
+
+ prefix0 = "\treturn "
+ prefix1 = "\t || "
+ prefix2 = "\t "
+
+ prefix = prefix0
+ for member in struct.members:
+ if member.cnt:
+ ret += f"\n{prefix }({{"
+ ret += f"\n{prefix2}\tbool err = false;"
+ ret += f"\n{prefix2}\tfor (typeof(val->{member.cnt}) i = 0; i < val->{member.cnt} && !err; i++)"
+ ret += f"\n{prefix2}\t\terr = marshal_{member.typ.name}(ctx, &val->{member.name}[i]));"
+ ret += f"\n{prefix2}\terr;"
+ ret += f"\n{prefix2}}})"
+ else:
+ ret += f"\n{prefix}marshal_{member.typ.name}(ctx, &val->{member.name})"
+ prefix = prefix1
+ ret += ";\n}\n"
+
+ # vtables ##################################################################
+ def msg_entry(msg: Struct) -> str:
+ ret = ""
+ ret += f"\t\t[{idprefix.upper()}TYP_{msg.name}] = {{\n"
+ ret += f"\t\t\tr.unmarshal_basesize = sizeof({c_typename(idprefix, msg)}),\n"
+ ret += f"\t\t\tr.unmarshal_extrasize = checksize_{msg.name},\n"
+ ret += f"\t\t\tr.unmarshal = unmarshal_{msg.name},\n"
+ ret += f"\t\t\tr.marshal = (_marshal_fn_t)marshal_{msg.name},\n"
+ ret += "\t\t}"
+ return ret
+ ret += f"""
+/* vtables ********************************************************************/
+
+struct _vtable_version _{idprefix}vtables[LIB9P_VER_NUM] = {{
+ [{idprefix.upper()}VER_UNINITIALIZED] = {{
+{msg_entry(next(msg for msg in structs if msg.name == 'Tversion'))},
+{msg_entry(next(msg for msg in structs if msg.name == 'Rversion'))},
+ }},
+"""
+ for ver in sorted(versions):
+ ret += f"\t[{c_ver(idprefix, ver)}] = {{\n"
+ for msg in structs:
+ if ver not in msg.msgver:
+ continue
+ ret += msg_entry(msg) + ",\n"
+ ret += "\t},\n"
+ ret += "};\n"
+
+ ############################################################################
+ return ret
+
+
+################################################################################
+
+class Parser:
+ cache: dict[str, tuple[str, list[Struct]]] = {}
+
+ def parse_file(self, filename: str) -> tuple[str, list[Struct]]:
+ if filename not in self.cache:
+ self.cache[filename] = parse_file(filename, self.parse_file)
+ return self.cache[filename]
+
+ def all(self) -> tuple[set[str], list[Struct]]:
+ ret_versions: set[str] = set()
+ ret_structs: dict[str, Struct] = {}
+ for (version, structs) in self.cache.values():
+ if version in ret_versions:
+ raise ValueError(f"duplicate protocol version {repr(version)}")
+ ret_versions.add(version)
+ for struct in structs:
+ if struct.name in ret_structs:
+ if struct != ret_structs[struct.name]:
+ raise ValueError(f"duplicate struct name {repr(struct.name)}")
+ else:
+ ret_structs[struct.name] = struct
+ return ret_versions, list(ret_structs.values())
+
+if __name__ == "__main__":
+ import sys
+
+ if len(sys.argv) < 2:
+ raise ValueError("requires at least 1 .txt filename")
+ parser = Parser()
+ for txtname in sys.argv[1:]:
+ parser.parse_file(txtname)
+ versions, structs = parser.all()
+ with open("include/lib9p/_types.h", "w") as fh:
+ fh.write(gen_h("lib9p_", versions, structs))
+ with open("types.c", "w") as fh:
+ fh.write(gen_c("lib9p_", versions, structs))
diff --git a/libcr/CMakeLists.txt b/libcr/CMakeLists.txt
new file mode 100644
index 0000000..ad7997f
--- /dev/null
+++ b/libcr/CMakeLists.txt
@@ -0,0 +1,10 @@
+# libcr/CMakeLists.txt - TODO
+#
+# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-Licence-Identifier: AGPL-3.0-or-later
+
+add_library(libcr INTERFACE)
+target_sources(libcr INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/coroutine.c
+)
+target_include_directories(libcr SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
diff --git a/libcr/coroutine.c b/libcr/coroutine.c
index 12d4a25..34a96b6 100644
--- a/libcr/coroutine.c
+++ b/libcr/coroutine.c
@@ -10,7 +10,7 @@
#include <assert.h>
#include <setjmp.h>
-#include "coroutine.h"
+#include "libcr/coroutine.h"
/* Configuration **************************************************************/
diff --git a/libcr/coroutine.h b/libcr/include/libcr/coroutine.h
index 4d83181..5c2d608 100644
--- a/libcr/coroutine.h
+++ b/libcr/include/libcr/coroutine.h
@@ -1,4 +1,4 @@
-/* coroutine.h - Simple embeddable coroutine implementation
+/* libcr/coroutine.h - Simple embeddable coroutine implementation
*
* Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-Licence-Identifier: AGPL-3.0-or-later
diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt
new file mode 100644
index 0000000..3efb6d9
--- /dev/null
+++ b/libcr_ipc/CMakeLists.txt
@@ -0,0 +1,10 @@
+# libcr_ipc/CMakeLists.txt - TODO
+#
+# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-Licence-Identifier: AGPL-3.0-or-later
+
+add_library(libcr_ipc INTERFACE)
+target_sources(libcr_ipc INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/sema.c
+)
+target_include_directories(libcr_ipc SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
diff --git a/libcr_ipc/coroutine_chan.h b/libcr_ipc/include/libcr_ipc/chan.h
index a3621a6..a3621a6 100644
--- a/libcr_ipc/coroutine_chan.h
+++ b/libcr_ipc/include/libcr_ipc/chan.h
diff --git a/libcr_ipc/coroutine_rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h
index 11d40d7..11d40d7 100644
--- a/libcr_ipc/coroutine_rpc.h
+++ b/libcr_ipc/include/libcr_ipc/rpc.h
diff --git a/libcr_ipc/coroutine_sema.h b/libcr_ipc/include/libcr_ipc/sema.h
index 57d5855..57d5855 100644
--- a/libcr_ipc/coroutine_sema.h
+++ b/libcr_ipc/include/libcr_ipc/sema.h
diff --git a/libcr_ipc/coroutine_sema.c b/libcr_ipc/sema.c
index a8b5ec4..a8b5ec4 100644
--- a/libcr_ipc/coroutine_sema.c
+++ b/libcr_ipc/sema.c
diff --git a/libnetio/CMakeLists.txt b/libnetio/CMakeLists.txt
new file mode 100644
index 0000000..226a2e5
--- /dev/null
+++ b/libnetio/CMakeLists.txt
@@ -0,0 +1,10 @@
+# libnetio/CMakeLists.txt - Build script for libnetio support library
+#
+# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-Licence-Identifier: AGPL-3.0-or-later
+
+add_library(libnetio INTERFACE)
+target_sources(libnetio INTERFACE
+ netio_posix.c
+)
+target_include_directories(libnetio SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
diff --git a/libusb/CMakeLists.txt b/libusb/CMakeLists.txt
new file mode 100644
index 0000000..8f015a1
--- /dev/null
+++ b/libusb/CMakeLists.txt
@@ -0,0 +1,23 @@
+# libusb/CMakeLists.txt - Build script for libusb support library
+#
+# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-Licence-Identifier: AGPL-3.0-or-later
+
+add_library(libusb INTERFACE)
+target_sources(libusb INTERFACE
+ usb_common.c
+)
+target_include_directories(libusb SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+add_custom_command(
+ OUTPUT ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.pdf
+ ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.txt
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.h
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.gen
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.gen
+)
+add_dependencies(generate
+ ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.pdf
+ ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.txt
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.h
+)
diff --git a/libusb/tusb_helpers.h b/libusb/include/libusb/tusb_helpers.h
index cd96357..cd96357 100644
--- a/libusb/tusb_helpers.h
+++ b/libusb/include/libusb/tusb_helpers.h
diff --git a/libusb/tusb_helpers.h.gen b/libusb/include/libusb/tusb_helpers.h.gen
index a348b16..213eda0 100755
--- a/libusb/tusb_helpers.h.gen
+++ b/libusb/include/libusb/tusb_helpers.h.gen
@@ -3,7 +3,7 @@
set -e
exec >"${0%.gen}"
cat <<'EOT'
-/* tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB
+/* libusb/tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB
*
* Copyright (c) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
*
@@ -29,10 +29,11 @@ cat <<'EOT'
*
*/
-#ifndef _USB_HELPERS_H_
-#define _USB_HELPERS_H_
+#ifndef _LIBUSB_TUSB_HELPERS_H_
+#define _LIBUSB_TUSB_HELPERS_H_
-/* USB 2.0 §9.6.7 "String" says "The list of currently defined USB LANGIDs can be found at
+/**
+ * USB 2.0 §9.6.7 "String" says "The list of currently defined USB LANGIDs can be found at
* http://www.usb.org/developers/docs.html.", but that page 404s.
*
* Once upon a time the USB-IF (usb.org) published a "Language Identifiers (LANGIDs)" version 1.0,
@@ -61,10 +62,9 @@ cat <<'EOT'
* to sort their list of by most-significant-byte was a poor editorial choice.
*/
EOT
-[ -d 3rd-party ] || mkdir 3rd-party
-[ -f 3rd-party/MS-LCID.pdf ] || wget -O 3rd-party/MS-LCID.pdf 'https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf'
-[ -f 3rd-party/MS-LCID.txt ] || pdftotext -layout 3rd-party/MS-LCID.pdf
-<3rd-party/MS-LCID.txt \
+[ -f ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.pdf ] || wget -O ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.pdf 'https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf'
+[ -f ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.txt ] || pdftotext -layout ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.pdf
+<${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.txt \
grep -E '^\s*0x[0-9A-F]{4}\s+[a-z]' | sed 's/,.*//' | grep -v reserved | # find the lines we're interested in
sed -E 's/^\s*0x(..)(..)\s+(\S.*)/\2 \1 \3/p' | tr '[:lower:]-' '[:upper:]_' | # format them as 'PRIhex SUBhex UPPER_STR'
sort |
@@ -72,11 +72,11 @@ EOT
column --table --output-separator=' '
cat <<'EOT'
-/* USB 2.0 §9.6.6 "Endpoint", field bEndpointAddress, bit 7 */
+/** USB 2.0 §9.6.6 "Endpoint", field bEndpointAddress, bit 7 */
#define TUD_ENDPOINT_OUT 0x00
#define TUD_ENDPOINT_IN 0x80
#define TU_UTF16(str) u ## str
-#endif /* _USB_HELPERS_H_ */
+#endif /* _LIBUSB_TUSB_HELPERS_H_ */
EOT
diff --git a/libusb/usb_common.h b/libusb/include/libusb/usb_common.h
index 3b45246..3b45246 100644
--- a/libusb/usb_common.h
+++ b/libusb/include/libusb/usb_common.h