📄 m4sugar.m4
字号:
m4_define([m4_cr_symbols2],m4_defn([m4_cr_symbols1])dnlm4_defn([m4_cr_digits])dnl)# m4_re_escape(STRING)# --------------------# Escape RE active characters in STRING.m4_define([m4_re_escape],[m4_bpatsubst([$1], [[][*+.?\^$]], [\\\&])])# m4_re_string# ------------# Regexp for `[a-zA-Z_0-9]*'# m4_dquote provides literal [] for the character class.m4_define([m4_re_string],m4_dquote(m4_defn([m4_cr_symbols2]))dnl[*]dnl)# m4_re_word# ----------# Regexp for `[a-zA-Z_][a-zA-Z_0-9]*'m4_define([m4_re_word],m4_dquote(m4_defn([m4_cr_symbols1]))dnlm4_defn([m4_re_string])dnl)# m4_tolower(STRING)# m4_toupper(STRING)# ------------------# These macros lowercase and uppercase strings.m4_define([m4_tolower],[m4_translit([$1], m4_defn([m4_cr_LETTERS]), m4_defn([m4_cr_letters]))])m4_define([m4_toupper],[m4_translit([$1], m4_defn([m4_cr_letters]), m4_defn([m4_cr_LETTERS]))])# m4_split(STRING, [REGEXP])# --------------------------## Split STRING into an m4 list of quoted elements. The elements are# quoted with [ and ]. Beginning spaces and end spaces *are kept*.# Use m4_strip to remove them.## REGEXP specifies where to split. Default is [\t ]+.## If STRING is empty, the result is an empty list.## Pay attention to the m4_changequotes. When m4 reads the definition of# m4_split, it still has quotes set to [ and ]. Luckily, these are matched# in the macro body, so the definition is stored correctly.## Also, notice that $1 is quoted twice, since we want the result to# be quoted. Then you should understand that the argument of# patsubst is ``STRING'' (i.e., with additional `` and '').## This macro is safe on active symbols, i.e.:# m4_define(active, ACTIVE)# m4_split([active active ])end# => [active], [active], []endm4_define([m4_split],[m4_ifval([$1], [_m4_split($@)])])m4_define([_m4_split],[m4_changequote(``, '')dnl[dnl Can't use m4_default here instead of m4_if, because m4_default usesdnl [ and ] as quotes.m4_bpatsubst(````$1'''', m4_if(``$2'',, ``[ ]+'', ``$2''), ``], ['')]dnlm4_changequote([, ])])# m4_flatten(STRING)# ------------------# If STRING contains end of lines, replace them with spaces. If there# are backslashed end of lines, remove them. This macro is safe with# active symbols.# m4_define(active, ACTIVE)# m4_flatten([active# act\# ive])end# => active activeendm4_define([m4_flatten],[m4_translit(m4_bpatsubst([[[$1]]], [\\]), [], [ ])])# m4_strip(STRING)# ----------------# Expands into STRING with tabs and spaces singled out into a single# space, and removing leading and trailing spaces.## This macro is robust to active symbols.# m4_define(active, ACTIVE)# m4_strip([ active <tab> <tab>active ])end# => active activeend## Because we want to preserve active symbols, STRING must be double-quoted.## Then notice the 2 last patterns: they are in charge of removing the# leading/trailing spaces. Why not just `[^ ]'? Because they are# applied to doubly quoted strings, i.e. more or less [[STRING]]. So# if there is a leading space in STRING, then it is the *third*# character, since there are two leading `['; equally for the last pattern.m4_define([m4_strip],[m4_bpatsubsts([[$1]], [[ ]+], [ ], [^\(..\) ], [\1], [ \(..\)$], [\1])])# m4_normalize(STRING)# --------------------# Apply m4_flatten and m4_strip to STRING.## The argument is quoted, so that the macro is robust to active symbols:## m4_define(active, ACTIVE)# m4_normalize([ act\# ive# active ])end# => active activeendm4_define([m4_normalize],[m4_strip(m4_flatten([$1]))])# m4_join(SEP, ARG1, ARG2...)# ---------------------------# Produce ARG1SEPARG2...SEPARGn.m4_defun([m4_join],[m4_case([$#], [1], [], [2], [[$2]], [[$2][$1]$0([$1], m4_shiftn(2, $@))])])# m4_append(MACRO-NAME, STRING, [SEPARATOR])# ------------------------------------------# Redefine MACRO-NAME to hold its former content plus `SEPARATOR`'STRING'# at the end. It is valid to use this macro with MACRO-NAME undefined,# in which case no SEPARATOR is added. Be aware that the criterion is# `not being defined', and not `not being empty'.## This macro is robust to active symbols. It can be used to grow# strings.## | m4_define(active, ACTIVE)# | m4_append([sentence], [This is an])# | m4_append([sentence], [ active ])# | m4_append([sentence], [symbol.])# | sentence# | m4_undefine([active])dnl# | sentence# => This is an ACTIVE symbol.# => This is an active symbol.## It can be used to define hooks.## | m4_define(active, ACTIVE)# | m4_append([hooks], [m4_define([act1], [act2])])# | m4_append([hooks], [m4_define([act2], [active])])# | m4_undefine([active])# | act1# | hooks# | act1# => act1# =># => activem4_define([m4_append],[m4_define([$1], m4_ifdef([$1], [m4_defn([$1])$3])[$2])])# m4_append_uniq(MACRO-NAME, STRING, [SEPARATOR])# -----------------------------------------------# As `m4_append', but append only if not yet present.m4_define([m4_append_uniq],[m4_ifdef([$1], [m4_bmatch([$3]m4_defn([$1])[$3], m4_re_escape([$3$2$3]), [], [m4_append($@)])], [m4_append($@)])])# m4_text_wrap(STRING, [PREFIX], [FIRST-PREFIX], [WIDTH])# -------------------------------------------------------# Expands into STRING wrapped to hold in WIDTH columns (default = 79).# If PREFIX is given, each line is prefixed with it. If FIRST-PREFIX is# specified, then the first line is prefixed with it. As a special case,# if the length of FIRST-PREFIX is greater than that of PREFIX, then# FIRST-PREFIX will be left alone on the first line.## Typical outputs are:## m4_text_wrap([Short string */], [ ], [/* ], 20)# => /* Short string */## m4_text_wrap([Much longer string */], [ ], [/* ], 20)# => /* Much longer# => string */## m4_text_wrap([Short doc.], [ ], [ --short ], 30)# => --short Short doc.## m4_text_wrap([Short doc.], [ ], [ --too-wide ], 30)# => --too-wide# => Short doc.## m4_text_wrap([Super long documentation.], [ ], [ --too-wide ], 30)# => --too-wide# => Super long# => documentation.## FIXME: there is no checking of a longer PREFIX than WIDTH, but do# we really want to bother with people trying each single corner# of a software?## This macro does not leave a trailing space behind the last word,# what complicates it a bit. The algorithm is stupid simple: all the# words are preceded by m4_Separator which is defined to empty for the# first word, and then ` ' (single space) for all the others.m4_define([m4_text_wrap],[m4_pushdef([m4_Prefix], [$2])dnlm4_pushdef([m4_Prefix1], m4_default([$3], [m4_Prefix]))dnlm4_pushdef([m4_Width], m4_default([$4], 79))dnlm4_pushdef([m4_Cursor], m4_qlen(m4_Prefix1))dnlm4_pushdef([m4_Separator], [])dnlm4_Prefix1[]dnlm4_if(m4_eval(m4_qlen(m4_Prefix1) > m4_len(m4_Prefix)), 1, [m4_define([m4_Cursor], m4_len(m4_Prefix))m4_Prefix], m4_if(m4_eval(m4_qlen(m4_Prefix1) < m4_len(m4_Prefix)), [0], [], [m4_define([m4_Cursor], m4_len(m4_Prefix))[]dnlm4_for(m4_Space, m4_qlen(m4_Prefix1), m4_eval(m4_len(m4_Prefix) - 1), [], [ ])])[]dnl)[]dnlm4_foreach_w([m4_Word], [$1],[m4_define([m4_Cursor], m4_eval(m4_Cursor + m4_qlen(m4_defn([m4_Word])) + 1))dnldnl New line if too long, else insert a space unless it is the firstdnl of the words.m4_if(m4_eval(m4_Cursor > m4_Width), 1, [m4_define([m4_Cursor], m4_eval(m4_len(m4_Prefix) + m4_qlen(m4_defn([m4_Word])) + 1))]m4_Prefix, [m4_Separator])[]dnlm4_defn([m4_Word])[]dnlm4_define([m4_Separator], [ ])])dnlm4_popdef([m4_Separator])dnlm4_popdef([m4_Cursor])dnlm4_popdef([m4_Width])dnlm4_popdef([m4_Prefix1])dnlm4_popdef([m4_Prefix])dnl])# m4_text_box(MESSAGE, [FRAME-CHARACTER = `-'])# ---------------------------------------------m4_define([m4_text_box],[@%:@@%:@ m4_bpatsubst([$1], [.], m4_if([$2], [], [[-]], [[$2]])) @%:@@%:@@%:@@%:@ $1 @%:@@%:@@%:@@%:@ m4_bpatsubst([$1], [.], m4_if([$2], [], [[-]], [[$2]])) @%:@@%:@[]dnl])# m4_qlen(STRING)# ---------------# Expands to the length of STRING after autom4te converts all quadrigraphs.m4_define([m4_qlen],[m4_len(m4_bpatsubsts([[$1]], [@\(<:\|:>\|S|\|%:\)@], [P], [@&t@]))])# m4_qdelta(STRING)# -----------------# Expands to the net change in the length of STRING from autom4te converting the# quadrigraphs in STRING. This number is always negative or zero.m4_define([m4_qdelta],[m4_eval(m4_qlen([$1]) - m4_len([$1]))])## ----------------------- #### 10. Number processing. #### ----------------------- ### m4_sign(A)# ----------## The sign of the integer A.m4_define([m4_sign],[m4_bmatch([$1], [^-], -1, [^0+], 0, 1)])# m4_cmp(A, B)# ------------## Compare two integers.# A < B -> -1# A = B -> 0# A > B -> 1m4_define([m4_cmp],[m4_sign(m4_eval([$1 - $2]))])# m4_list_cmp(A, B)# -----------------## Compare the two lists of integers A and B. For instance:# m4_list_cmp((1, 0), (1)) -> 0# m4_list_cmp((1, 0), (1, 0)) -> 0# m4_list_cmp((1, 2), (1, 0)) -> 1# m4_list_cmp((1, 2, 3), (1, 2)) -> 1# m4_list_cmp((1, 2, -3), (1, 2)) -> -1# m4_list_cmp((1, 0), (1, 2)) -> -1# m4_list_cmp((1), (1, 2)) -> -1m4_define([m4_list_cmp],[m4_if([$1$2], [()()], 0, [$1], [()], [$0((0), [$2])], [$2], [()], [$0([$1], (0))], [m4_case(m4_cmp(m4_car$1, m4_car$2), -1, -1, 1, 1, 0, [$0((m4_shift$1), (m4_shift$2))])])])## ------------------------ #### 11. Version processing. #### ------------------------ ### m4_version_unletter(VERSION)# ----------------------------# Normalize beta version numbers with letters to numbers only for comparison.## Nl -> (N+1).-1.(l#)##i.e., 2.14a -> 2.15.-1.1, 2.14b -> 2.15.-1.2, etc.# This macro is absolutely not robust to active macro, it expects# reasonable version numbers and is valid up to `z', no double letters.m4_define([m4_version_unletter],[m4_translit(m4_bpatsubsts([$1], [\([0-9]+\)\([abcdefghi]\)], [m4_eval(\1 + 1).-1.\2], [\([0-9]+\)\([jklmnopqrs]\)], [m4_eval(\1 + 1).-1.1\2], [\([0-9]+\)\([tuvwxyz]\)], [m4_eval(\1 + 1).-1.2\2]), [abcdefghijklmnopqrstuvwxyz], [12345678901234567890123456])])# m4_version_compare(VERSION-1, VERSION-2)# ----------------------------------------# Compare the two version numbers and expand into# -1 if VERSION-1 < VERSION-2# 0 if =# 1 if >m4_define([m4_version_compare],[m4_list_cmp((m4_split(m4_version_unletter([$1]), [\.])), (m4_split(m4_version_unletter([$2]), [\.])))])# m4_PACKAGE_NAME# m4_PACKAGE_TARNAME# m4_PACKAGE_VERSION# m4_PACKAGE_STRING# m4_PACKAGE_BUGREPORT# --------------------m4_include([m4sugar/version.m4])# m4_version_prereq(VERSION, [IF-OK], [IF-NOT = FAIL])# ----------------------------------------------------# Check this Autoconf version against VERSION.m4_define([m4_version_prereq],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Autoconf version $1 or higher is required], 63)])], [$2])[]dnl])## ------------------- #### 12. File handling. #### ------------------- ### It is a real pity that M4 comes with no macros to bind a diversion# to a file. So we have to deal without, which makes us a lot more# fragile that we should.# m4_file_append(FILE-NAME, CONTENT)# ----------------------------------m4_define([m4_file_append],[m4_syscmd([cat >>$1 <<_m4eof$2_m4eof])m4_if(m4_sysval, [0], [], [m4_fatal([$0: cannot write: $1])])])## ------------------------ #### 13. Setting M4sugar up. #### ------------------------ ### m4_init# -------m4_define([m4_init],[# All the M4sugar macros start with `m4_', except `dnl' kept as is# for sake of simplicity.m4_pattern_forbid([^_?m4_])m4_pattern_forbid([^dnl$])# _m4_divert_diversion should be defined:m4_divert_push([KILL])# Check the divert push/pop perfect balance.m4_wrap([m4_divert_pop([]) m4_ifdef([_m4_divert_diversion], [m4_fatal([$0: unbalanced m4_divert_push:]_m4_divert_n_stack)])[]])])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -