{
    "content": [
        {
            "type": "text",
            "text": "# PERLHACKTUT (man)\n\n## NAME\n\nperlhacktut - Walk through the creation of a simple C code patch\n\n## DESCRIPTION\n\nThis document takes you through a simple patch example.\n\n## Sections\n\n- **NAME**\n- **DESCRIPTION**\n- **EXAMPLE OF A SIMPLE PATCH** (4 subsections)\n- **AUTHOR**\n\nUse structuredContent.sections for detailed options, examples, and full documentation.\n"
        }
    ],
    "structuredContent": {
        "command": "PERLHACKTUT",
        "section": "",
        "mode": "man",
        "summary": "perlhacktut - Walk through the creation of a simple C code patch",
        "synopsis": null,
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [],
        "see_also": [],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "DESCRIPTION",
                "lines": 7,
                "subsections": []
            },
            {
                "name": "EXAMPLE OF A SIMPLE PATCH",
                "lines": 9,
                "subsections": [
                    {
                        "name": "Writing the patch",
                        "lines": 74
                    },
                    {
                        "name": "Testing the patch",
                        "lines": 44
                    },
                    {
                        "name": "Documenting the patch",
                        "lines": 14
                    },
                    {
                        "name": "Submit",
                        "lines": 2
                    }
                ]
            },
            {
                "name": "AUTHOR",
                "lines": 6,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "perlhacktut - Walk through the creation of a simple C code patch\n",
                "subsections": []
            },
            "DESCRIPTION": {
                "content": "This document takes you through a simple patch example.\n\nIf you haven't read perlhack yet, go do that first! You might also want to read through\nperlsource too.\n\nOnce you're done here, check out perlhacktips next.\n",
                "subsections": []
            },
            "EXAMPLE OF A SIMPLE PATCH": {
                "content": "Let's take a simple patch from start to finish.\n\nHere's something Larry suggested: if a \"U\" is the first active format during a \"pack\", (for\nexample, \"pack \"U3C8\", @stuff\") then the resulting string should be treated as UTF-8 encoded.\n\nIf you are working with a git clone of the Perl repository, you will want to create a branch\nfor your changes. This will make creating a proper patch much simpler. See the perlgit for\ndetails on how to do this.\n",
                "subsections": [
                    {
                        "name": "Writing the patch",
                        "content": "How do we prepare to fix this up? First we locate the code in question - the \"pack\" happens\nat runtime, so it's going to be in one of the pp files. Sure enough, \"pppack\" is in pp.c.\nSince we're going to be altering this file, let's copy it to pp.c~.\n\n[Well, it was in pp.c when this tutorial was written. It has now been split off with\n\"ppunpack\" to its own file, pppack.c]\n\nNow let's look over \"pppack\": we take a pattern into \"pat\", and then loop over the pattern,\ntaking each format character in turn into \"datumtype\". Then for each possible format\ncharacter, we swallow up the other arguments in the pattern (a field width, an asterisk, and\nso on) and convert the next chunk input into the specified format, adding it onto the output\nSV \"cat\".\n\nHow do we know if the \"U\" is the first format in the \"pat\"? Well, if we have a pointer to the\nstart of \"pat\" then, if we see a \"U\" we can test whether we're still at the start of the\nstring. So, here's where \"pat\" is set up:\n\nSTRLEN fromlen;\nchar *pat = SvPVx(*++MARK, fromlen);\nchar *patend = pat + fromlen;\nI32 len;\nI32 datumtype;\nSV *fromstr;\n\nWe'll have another string pointer in there:\n\nSTRLEN fromlen;\nchar *pat = SvPVx(*++MARK, fromlen);\nchar *patend = pat + fromlen;\n+  char *patcopy;\nI32 len;\nI32 datumtype;\nSV *fromstr;\n\nAnd just before we start the loop, we'll set \"patcopy\" to be the start of \"pat\":\n\nitems = SP - MARK;\nMARK++;\nSvPVCLEAR(cat);\n+  patcopy = pat;\nwhile (pat < patend) {\n\nNow if we see a \"U\" which was at the start of the string, we turn on the \"UTF8\" flag for the\noutput SV, \"cat\":\n\n+  if (datumtype == 'U' && pat==patcopy+1)\n+      SvUTF8on(cat);\nif (datumtype == '#') {\nwhile (pat < patend && *pat != '\\n')\npat++;\n\nRemember that it has to be \"patcopy+1\" because the first character of the string is the \"U\"\nwhich has been swallowed into \"datumtype!\"\n\nOops, we forgot one thing: what if there are spaces at the start of the pattern? \"pack(\"\nU*\", @stuff)\" will have \"U\" as the first active character, even though it's not the first\nthing in the pattern. In this case, we have to advance \"patcopy\" along with \"pat\" when we see\nspaces:\n\nif (isSPACE(datumtype))\ncontinue;\n\nneeds to become\n\nif (isSPACE(datumtype)) {\npatcopy++;\ncontinue;\n}\n\nOK. That's the C part done. Now we must do two additional things before this patch is ready\nto go: we've changed the behaviour of Perl, and so we must document that change. We must also\nprovide some more regression tests to make sure our patch works and doesn't create a bug\nsomewhere else along the line.\n"
                    },
                    {
                        "name": "Testing the patch",
                        "content": "The regression tests for each operator live in t/op/, and so we make a copy of t/op/pack.t to\nt/op/pack.t~. Now we can add our tests to the end. First, we'll test that the \"U\" does indeed\ncreate Unicode strings.\n\nt/op/pack.t has a sensible ok() function, but if it didn't we could use the one from\nt/test.pl.\n\nrequire './test.pl';\nplan( tests => 159 );\n\nso instead of this:\n\nprint 'not ' unless \"1.20.300.4000\" eq sprintf \"%vd\",\npack(\"U*\",1,20,300,4000);\nprint \"ok $test\\n\"; $test++;\n\nwe can write the more sensible (see Test::More for a full explanation of is() and other\ntesting functions).\n\nis( \"1.20.300.4000\", sprintf \"%vd\", pack(\"U*\",1,20,300,4000),\n\"U* produces Unicode\" );\n\nNow we'll test that we got that space-at-the-beginning business right:\n\nis( \"1.20.300.4000\", sprintf \"%vd\", pack(\"  U*\",1,20,300,4000),\n\"  with spaces at the beginning\" );\n\nAnd finally we'll test that we don't make Unicode strings if \"U\" is not the first active\nformat:\n\nisnt( v1.20.300.4000, sprintf \"%vd\", pack(\"C0U*\",1,20,300,4000),\n\"U* not first isn't Unicode\" );\n\nMustn't forget to change the number of tests which appears at the top, or else the automated\ntester will get confused. This will either look like this:\n\nprint \"1..156\\n\";\n\nor this:\n\nplan( tests => 156 );\n\nWe now compile up Perl, and run it through the test suite. Our new tests pass, hooray!\n"
                    },
                    {
                        "name": "Documenting the patch",
                        "content": "Finally, the documentation. The job is never done until the paperwork is over, so let's\ndescribe the change we've just made. The relevant place is pod/perlfunc.pod; again, we make a\ncopy, and then we'll insert this text in the description of \"pack\":\n\n=item *\n\nIf the pattern begins with a C<U>, the resulting string will be treated\nas UTF-8-encoded Unicode. You can force UTF-8 encoding on in a string\nwith an initial C<U0>, and the bytes that follow will be interpreted as\nUnicode characters. If you don't want this to happen, you can begin\nyour pattern with C<C0> (or anything else) to force Perl not to UTF-8\nencode your string, and then follow this with a C<U*> somewhere in your\npattern.\n"
                    },
                    {
                        "name": "Submit",
                        "content": "See perlhack for details on how to submit this patch.\n"
                    }
                ]
            },
            "AUTHOR": {
                "content": "This document was originally written by Nathan Torkington, and is maintained by the\nperl5-porters mailing list.\n\n\n\nperl v5.34.0                                 2026-06-23                               PERLHACKTUT(1)",
                "subsections": []
            }
        }
    }
}