2024-04-05 14:50:45 -07:00
#!/usr/bin/env python
#
# ====- Generate documentation for libc functions ------------*- python -*--==#
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# ==-------------------------------------------------------------------------==#
from argparse import ArgumentParser , Namespace
from pathlib import Path
from typing import Dict
2024-12-12 09:21:04 -08:00
import os
import sys
2024-12-12 13:17:51 -08:00
import yaml
2024-04-05 14:50:45 -07:00
2024-05-23 12:48:16 -05:00
from header import Header
class DocgenAPIFormatError ( Exception ) :
""" Raised on fatal formatting errors with a description of a formatting error """
def check_api ( header : Header , api : Dict ) :
"""
2024-12-12 13:17:51 -08:00
Checks that docgen yaml files are properly formatted . If there are any
2024-05-23 12:48:16 -05:00
fatal formatting errors , raises exceptions with error messages useful for
fixing formatting . Warnings are printed to stderr on non - fatal formatting
errors . The code that runs after ` ` check_api ( api ) ` ` is called expects that
2024-12-12 13:17:51 -08:00
` ` check_api ` ` executed without raising formatting exceptions so the yaml
2024-05-23 12:48:16 -05:00
matches the formatting specified here .
2024-12-12 13:17:51 -08:00
The yaml file may contain :
2024-05-23 12:48:16 -05:00
* an optional macros object
* an optional functions object
Formatting of ` ` macros ` ` and ` ` functions ` ` objects
== == == == == == == == == == == == == == == == == == == == == == == == ==
If a macros or functions object is present , then it may contain nested
objects . Each of these nested objects should have a name matching a macro
or function ' s name, and each nested object must have the property:
` ` " c-definition " ` ` or ` ` " posix-definition " ` ` .
Description of properties
== == == == == == == == == == == == =
The defined property is intended to be a reference to a part of the
standard that defines the function or macro . For the ` ` " c-definition " ` ` property ,
this should be a C standard section number . For the ` ` " posix-definition " ` ` property ,
this should be a link to the definition .
2024-12-12 13:17:51 -08:00
: param api : docgen yaml file contents parsed into a dict
2024-05-23 12:48:16 -05:00
"""
errors = [ ]
2024-12-12 10:49:55 -08:00
# We require entries to have at least one of these.
possible_keys = [
" c-definition " ,
" in-latest-posix " ,
" removed-in-posix-2008 " ,
2025-02-11 14:14:41 -08:00
" removed-in-posix-2024 " ,
2024-12-12 10:49:55 -08:00
]
2024-05-23 12:48:16 -05:00
# Validate macros
if " macros " in api :
if not header . macro_file_exists ( ) :
print (
f " warning: Macro definitions are listed for { header . name } , but no macro file can be found in the directory tree rooted at { header . macros_dir } . All macros will be listed as not implemented. " ,
file = sys . stderr ,
)
macros = api [ " macros " ]
for name , obj in macros . items ( ) :
2024-12-12 10:49:55 -08:00
if not any ( k in obj for k in possible_keys ) :
err = f " error: Macro { name } does not contain at least one required property: { possible_keys } "
2024-05-23 12:48:16 -05:00
errors . append ( err )
# Validate functions
if " functions " in api :
if not header . fns_dir_exists ( ) :
print (
f " warning: Function definitions are listed for { header . name } , but no function implementation directory exists at { header . fns_dir } . All functions will be listed as not implemented. " ,
file = sys . stderr ,
)
fns = api [ " functions " ]
for name , obj in fns . items ( ) :
2024-12-12 10:49:55 -08:00
if not any ( k in obj for k in possible_keys ) :
err = f " error: function { name } does not contain at least one required property: { possible_keys } "
2024-05-23 12:48:16 -05:00
errors . append ( err )
if errors :
raise DocgenAPIFormatError ( " \n " . join ( errors ) )
def load_api ( header : Header ) - > Dict :
2024-12-12 13:17:51 -08:00
api = header . docgen_yaml . read_text ( encoding = " utf-8 " )
return yaml . safe_load ( api )
2024-04-05 14:50:45 -07:00
2024-12-04 15:43:52 -08:00
def print_tbl_dir ( name ) :
2024-05-23 12:48:16 -05:00
print (
f """
. . list - table : :
: widths : auto
: align : center
: header - rows : 1
2024-12-04 15:43:52 -08:00
* - { name }
2024-05-23 12:48:16 -05:00
- Implemented
- C23 Standard Section
2024-12-12 10:49:55 -08:00
- POSIX Docs """
2024-04-11 23:49:59 +08:00
)
2024-04-12 14:35:10 -07:00
2024-05-23 12:48:16 -05:00
def print_functions_rst ( header : Header , functions : Dict ) :
tbl_hdr = " Functions "
print ( tbl_hdr )
print ( " = " * len ( tbl_hdr ) )
2024-12-04 15:43:52 -08:00
print_tbl_dir ( " Function " )
2024-05-23 12:48:16 -05:00
for name in sorted ( functions . keys ( ) ) :
print ( f " * - { name } " )
if header . fns_dir_exists ( ) and header . implements_fn ( name ) :
print ( " - |check| " )
else :
print ( " - " )
if " c-definition " in functions [ name ] :
print ( f ' - { functions [ name ] [ " c-definition " ] } ' )
else :
print ( " - " )
2024-12-12 10:49:55 -08:00
if " in-latest-posix " in functions [ name ] :
print (
f " - `POSIX.1-2024 <https://pubs.opengroup.org/onlinepubs/9799919799/functions/ { name } .html>`__ "
)
elif " removed-in-posix-2008 " in functions [ name ] :
print (
f " - `removed in POSIX.1-2008 <https://pubs.opengroup.org/onlinepubs/007904875/functions/ { name } .html>`__ "
)
2025-02-11 14:14:41 -08:00
elif " removed-in-posix-2024 " in functions [ name ] :
print (
f " - `removed in POSIX.1-2024 <https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/ { name } .html>`__ "
)
2024-05-23 12:48:16 -05:00
else :
print ( " - " )
2024-04-12 14:35:10 -07:00
2024-04-11 23:49:59 +08:00
2024-05-23 12:48:16 -05:00
def print_macros_rst ( header : Header , macros : Dict ) :
tbl_hdr = " Macros "
print ( tbl_hdr )
print ( " = " * len ( tbl_hdr ) )
2024-04-05 14:50:45 -07:00
2024-12-04 15:43:52 -08:00
print_tbl_dir ( " Macro " )
2024-04-05 14:50:45 -07:00
2024-05-23 12:48:16 -05:00
for name in sorted ( macros . keys ( ) ) :
print ( f " * - { name } " )
2024-04-05 14:50:45 -07:00
2024-05-23 12:48:16 -05:00
if header . macro_file_exists ( ) and header . implements_macro ( name ) :
2024-04-05 14:50:45 -07:00
print ( " - |check| " )
else :
print ( " - " )
2024-05-23 12:48:16 -05:00
if " c-definition " in macros [ name ] :
print ( f ' - { macros [ name ] [ " c-definition " ] } ' )
2024-04-05 14:50:45 -07:00
else :
print ( " - " )
2024-12-12 10:49:55 -08:00
if " in-latest-posix " in macros [ name ] :
print (
f " - `POSIX.1-2024 <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/ { header . name } .html>`__ "
)
2024-05-23 12:48:16 -05:00
else :
print ( " - " )
print ( )
2024-04-05 14:50:45 -07:00
2024-05-23 12:48:16 -05:00
def print_impl_status_rst ( header : Header , api : Dict ) :
2024-12-12 09:21:04 -08:00
if os . sep in header . name :
print ( " .. include:: ../../check.rst \n " )
else :
print ( " .. include:: ../check.rst \n " )
2024-04-05 14:50:45 -07:00
2024-05-23 12:48:16 -05:00
print ( " = " * len ( header . name ) )
print ( header . name )
print ( " = " * len ( header . name ) )
print ( )
# the macro and function sections are both optional
if " macros " in api :
print_macros_rst ( header , api [ " macros " ] )
if " functions " in api :
print_functions_rst ( header , api [ " functions " ] )
2024-04-05 14:50:45 -07:00
2024-12-12 13:17:51 -08:00
# This code implicitly relies on docgen.py being in the same dir as the yaml
2024-12-12 09:21:04 -08:00
# files and is likely to need to be fixed when re-integrating docgen into
# hdrgen.
2024-12-12 09:47:51 -08:00
def get_choices ( ) - > list :
2024-12-12 09:21:04 -08:00
choices = [ ]
2024-12-12 13:17:51 -08:00
for path in Path ( __file__ ) . parent . rglob ( " *.yaml " ) :
2024-12-12 09:21:04 -08:00
fname = path . with_suffix ( " .h " ) . name
if path . parent != Path ( __file__ ) . parent :
fname = path . parent . name + os . sep + fname
choices . append ( fname )
return choices
2024-04-05 14:50:45 -07:00
def parse_args ( ) - > Namespace :
parser = ArgumentParser ( )
2024-12-12 09:21:04 -08:00
parser . add_argument ( " header_name " , choices = get_choices ( ) )
2024-04-05 14:50:45 -07:00
return parser . parse_args ( )
if __name__ == " __main__ " :
args = parse_args ( )
2024-05-23 12:48:16 -05:00
header = Header ( args . header_name )
api = load_api ( header )
check_api ( header , api )
2024-04-05 14:50:45 -07:00
2024-05-23 12:48:16 -05:00
print_impl_status_rst ( header , api )